摘要:雖然構(gòu)造函數(shù)或者對(duì)象字面量的方法都可以用來(lái)創(chuàng)建對(duì)象,但是這些方法使用同一個(gè)接口創(chuàng)建很多對(duì)象,會(huì)產(chǎn)生大量的重復(fù)代碼。參考資料冴羽的專(zhuān)題系列中高級(jí)前端面試手寫(xiě)代碼無(wú)敵秘籍前端筆試之手寫(xiě)代碼一
本系列會(huì)從面試的角度出發(fā)圍繞JavaScript,Node.js(npm包)以及框架三個(gè)方面來(lái)對(duì)常見(jiàn)的模擬實(shí)現(xiàn)進(jìn)行總結(jié),具體源代碼放在github項(xiàng)目上,長(zhǎng)期更新和維護(hù)
數(shù)組去重
(一維)數(shù)組去重最原始的方法就是使用雙層循環(huán),分別循環(huán)原始數(shù)組和新建數(shù)組;或者我們可以使用indexOf來(lái)簡(jiǎn)化內(nèi)層的循環(huán);或者可以將原始數(shù)組排序完再來(lái)去重,這樣會(huì)減少一個(gè)循環(huán),只需要比較前后兩個(gè)數(shù)即可;當(dāng)然我們可以使用ES5,ES6的方法來(lái)簡(jiǎn)化去重的寫(xiě)法,比如我們可以使用filter來(lái)簡(jiǎn)化內(nèi)層循環(huán),或者使用Set、Map、擴(kuò)展運(yùn)算符這些用起來(lái)更簡(jiǎn)單的方法,但是效率上應(yīng)該不會(huì)比原始方法好。二維數(shù)組的去重可以在上面方法的基礎(chǔ)上再判斷元素是不是數(shù)組,如果是的話,就進(jìn)行遞歸處理。
雙層循環(huán)
var array = [1, 1, "1", "1"]; function unique(array) { var res = []; for (var i = 0, arrayLen = array.length; i < arrayLen; i++) { for (var j = 0, resLen = res.length; j < resLen; j++ ) { if (array[i] === res[j]) { break; } } if (j === resLen) { res.push(array[i]) } } return res; } console.log(unique(array)); // [1, "1"]
利用indexOf
var array = [1, 1, "1"]; function unique(array) { var res = []; for (var i = 0, len = array.length; i < len; i++) { var current = array[i]; if (res.indexOf(current) === -1) { res.push(current) } } return res; } console.log(unique(array));
排序后去重
var array = [1, 1, "1"]; function unique(array) { var res = []; var sortedArray = array.concat().sort(); var seen; for (var i = 0, len = sortedArray.length; i < len; i++) { // 如果是第一個(gè)元素或者相鄰的元素不相同 if (!i || seen !== sortedArray[i]) { res.push(sortedArray[i]) } seen = sortedArray[i]; } return res; } console.log(unique(array));
filter
filter可以用來(lái)簡(jiǎn)化外層循環(huán)
使用indexOf:
var array = [1, 2, 1, 1, "1"]; function unique(array) { var res = array.filter(function(item, index, array){ return array.indexOf(item) === index; }) return res; } console.log(unique(array));
排序去重:
var array = [1, 2, 1, 1, "1"]; function unique(array) { return array.concat().sort().filter(function(item, index, array){ return !index || item !== array[index - 1] }) } console.log(unique(array));
ES6方法
Set:
var array = [1, 2, 1, 1, "1"]; function unique(array) { return Array.from(new Set(array)); } console.log(unique(array)); // [1, 2, "1"]
再簡(jiǎn)化下
function unique(array) { return [...new Set(array)]; } //或者 var unique = (a) => [...new Set(a)]
Map:
function unique (arr) { const seen = new Map() return arr.filter((a) => !seen.has(a) && seen.set(a, 1)) }
類(lèi)型判斷
類(lèi)型判斷需要注意以下幾點(diǎn)
typeof對(duì)六個(gè)基本數(shù)據(jù)類(lèi)型Undefined、Null、Boolean、Number、String、Object(大寫(xiě))返回的結(jié)果是
undefined、object、boolean、number、string、object(小寫(xiě)),可以看到Null和Object 類(lèi)型都返回了 object 字符串;typeof卻能檢測(cè)出函數(shù)類(lèi)型;綜上,typeof能檢測(cè)出六種類(lèi)型,但是不能檢測(cè)出null類(lèi)型和Object下細(xì)分的類(lèi)型,如Array,Function,Date,RegExp,Error等。
Object.prototype.toString的作用非常強(qiáng)大,它能檢測(cè)出基本數(shù)據(jù)類(lèi)型以及Object下的細(xì)分類(lèi)型,甚至像 Math,JSON,arguments它都能檢測(cè)出它們的具體類(lèi)型,它返回結(jié)果形式例如[object Number](注意最后的數(shù)據(jù)類(lèi)型是大寫(xiě)).所以,Object.prototype.toString基本上能檢測(cè)出所有的類(lèi)型了,只不過(guò)有時(shí)需要考慮到兼容性低版本瀏覽器的問(wèn)題。
通用API
// 該類(lèi)型判斷函數(shù)可以判斷六種基本數(shù)據(jù)類(lèi)型以及Boolean Number String Function Array Date RegExp Object Error, // 其他類(lèi)型因?yàn)橛龅筋?lèi)型判斷的情況較少所以都會(huì)返回object,不在進(jìn)行詳細(xì)的判斷 // 比如ES6新增的Symbol,Map,Set等類(lèi)型 var classtype = {}; "Boolean Number String Function Array Date RegExp Object Error".split(" ").map(function(item) { classtype["[object " + item + "]"] = item.toLowerCase(); }) function type(obj) { // 解決IE6中null和undefined會(huì)被Object.prototype.toString識(shí)別成[object Object] if (obj == null) { return obj + ""; } //如果是typeof后類(lèi)型為object下的細(xì)分類(lèi)型(Array,Function,Date,RegExp,Error)或者是Object類(lèi)型,則要利用Object.prototype.toString //由于ES6新增的Symbol,Map,Set等類(lèi)型不在classtype列表中,所以使用type函數(shù),返回的結(jié)果會(huì)是object return typeof obj === "object" || typeof obj === "function" ? classtype[Object.prototype.toString.call(obj)] || "object" : typeof obj; }
判斷空對(duì)象
判斷是否有屬性,for循環(huán)一旦執(zhí)行,就說(shuō)明有屬性,此時(shí)返回false
function isEmptyObject( obj ) { var name; for ( name in obj ) { return false; } return true; } console.log(isEmptyObject({})); // true console.log(isEmptyObject([])); // true console.log(isEmptyObject(null)); // true console.log(isEmptyObject(undefined)); // true console.log(isEmptyObject(1)); // true console.log(isEmptyObject("")); // true console.log(isEmptyObject(true)); // true
我們可以看出isEmptyObject實(shí)際上判斷的并不僅僅是空對(duì)象。但是既然jQuery是這樣寫(xiě),可能是因?yàn)榭紤]到實(shí)際開(kāi)發(fā)中 isEmptyObject用來(lái)判斷 {} 和 {a: 1} 是足夠的吧。如果真的是只判斷 {},完全可以結(jié)合上篇寫(xiě)的 type函數(shù)篩選掉不適合的情況。
判斷Window對(duì)象
Window對(duì)象有一個(gè)window屬性指向自身,可以利用這個(gè)特性來(lái)判斷是否是Window對(duì)象
function isWindow( obj ) { return obj != null && obj === obj.window; }
判斷數(shù)組
isArray是數(shù)組類(lèi)型內(nèi)置的數(shù)據(jù)類(lèi)型判斷函數(shù),但是會(huì)有兼容性問(wèn)題,一個(gè)polyfill如下
isArray = Array.isArray || function(array){ return Object.prototype.toString.call(array) === "[object Array]"; }
判斷類(lèi)數(shù)組
jquery實(shí)現(xiàn)的isArrayLike,數(shù)組和類(lèi)數(shù)組都會(huì)返回true。所如果isArrayLike返回true,至少要滿(mǎn)足三個(gè)條件之一:
是數(shù)組
長(zhǎng)度為 0 比如下面情況,如果我們?nèi)サ鬺ength === 0 這個(gè)判斷,就會(huì)打印 false,然而我們都知道 arguments 是一個(gè)類(lèi)數(shù)組對(duì)象,這里是應(yīng)該返回 true 的
function a(){ console.log(isArrayLike(arguments)) } a();
lengths 屬性是大于 0 的數(shù)字類(lèi)型,并且obj[length - 1]必須存在(考慮到arr = [,,3]的情況)
function isArrayLike(obj) { // obj 必須有 length屬性 var length = !!obj && "length" in obj && obj.length; var typeRes = type(obj); // 排除掉函數(shù)和 Window 對(duì)象 if (typeRes === "function" || isWindow(obj)) { return false; } return typeRes === "array" || length === 0 || typeof length === "number" && length > 0 && (length - 1) in obj; }
判斷NaN
判斷一個(gè)數(shù)是不是NaN不能單純地使用 === 這樣來(lái)判斷, 因?yàn)?b>NaN不與任何數(shù)相等, 包括自身,注意在ES6的isNaN中只有值為數(shù)字類(lèi)型使用NaN才會(huì)返回true
isNaN: function(value){ return isNumber(value) && isNaN(value); }
判斷DOM元素
利用DOM對(duì)象特有的nodeType屬性(
isElement: function(obj){ return !!(obj && obj.nodeType === 1); // 兩次感嘆號(hào)將值轉(zhuǎn)化為布爾值 }
判斷arguments對(duì)象
低版本的瀏覽器中argument對(duì)象通過(guò)Object.prototype.toString判斷后返回的是[object Object],所以需要兼容
isArguments: function(obj){ return Object.prototype.toString.call(obj) === "[object Arguments]" || (obj != null && Object.hasOwnProperty.call(obj, "callee")); }
深淺拷貝
如果是數(shù)組,實(shí)現(xiàn)淺拷貝,比可以slice,concat返回一個(gè)新數(shù)組的特性來(lái)實(shí)現(xiàn);實(shí)現(xiàn)深拷貝,可以利用JSON.parse和JSON.stringify來(lái)實(shí)現(xiàn),但是有一個(gè)問(wèn)題,不能拷貝函數(shù)(此時(shí)拷貝后返回的數(shù)組為null)。上面的方法都屬于技巧,下面考慮怎么實(shí)現(xiàn)一個(gè)對(duì)象或者數(shù)組的深淺拷貝
淺拷貝
思路很簡(jiǎn)單,遍歷對(duì)象,然后把屬性和屬性值都放在一個(gè)新的對(duì)象就OK了
var shallowCopy = function(obj) { // 只拷貝對(duì)象 if (typeof obj !== "object") return; // 根據(jù)obj的類(lèi)型判斷是新建一個(gè)數(shù)組還是對(duì)象 var newObj = obj instanceof Array ? [] : {}; // 遍歷obj,并且判斷是obj的屬性才拷貝 for (var key in obj) { if (obj.hasOwnProperty(key)) { newObj[key] = obj[key]; } } return newObj; }
深拷貝
思路也很簡(jiǎn)單,就是在拷貝的時(shí)候判斷一下屬性值的類(lèi)型,如果是對(duì)象,就遞歸調(diào)用深淺拷貝函數(shù)就ok了
var deepCopy = function(obj) { if (typeof obj !== "object") return; var newObj = obj instanceof Array ? [] : {}; for (var key in obj) { if (obj.hasOwnProperty(key)) { newObj[key] = typeof obj[key] === "object" ? deepCopy(obj[key]) : obj[key]; } } return newObj; }
扁平化
遞歸
循環(huán)數(shù)組元素,如果還是一個(gè)數(shù)組,就遞歸調(diào)用該方法
// 方法 1 var arr = [1, [2, [3, 4]]]; function flatten(arr) { var result = []; for (var i = 0, len = arr.length; i < len; i++) { if (Array.isArray(arr[i])) { result = result.concat(flatten(arr[i])) } else { result.push(arr[i]) } } return result; } console.log(flatten(arr))
toString()
如果數(shù)組的元素都是數(shù)字,可以使用該方法
// 方法2 var arr = [1, [2, [3, 4]]]; function flatten(arr) { return arr.toString().split(",").map(function(item){ return +item // +會(huì)使字符串發(fā)生類(lèi)型轉(zhuǎn)換 }) } console.log(flatten(arr))
reduce()
// 方法3 var arr = [1, [2, [3, 4]]]; function flatten(arr) { return arr.reduce(function(prev, next){ return prev.concat(Array.isArray(next) ? flatten(next) : next) }, []) } console.log(flatten(arr))
...
// 扁平化一維數(shù)組 var arr = [1, [2, [3, 4]]]; console.log([].concat(...arr)); // [1, 2, [3, 4]] // 可以扁平化多維數(shù)組 var arr = [1, [2, [3, 4]]]; function flatten(arr) { while (arr.some(item => Array.isArray(item))) { arr = [].concat(...arr); } return arr; } console.log(flatten(arr))
柯里化
通用版
function curry(fn, args) { var length = fn.length; var args = args || []; return function(){ newArgs = args.concat(Array.prototype.slice.call(arguments)); if (newArgs.length < length) { return curry.call(this,fn,newArgs); }else{ return fn.apply(this,newArgs); } } } function multiFn(a, b, c) { return a * b * c; } var multi = curry(multiFn); multi(2)(3)(4); multi(2,3,4); multi(2)(3,4); multi(2,3)(4);
ES6版
const curry = (fn, arr = []) => (...args) => ( arg => arg.length === fn.length ? fn(...arg) : curry(fn, arg) )([...arr, ...args]) let curryTest=curry((a,b,c,d)=>a+b+c+d) curryTest(1,2,3)(4) //返回10 curryTest(1,2)(4)(3) //返回10 curryTest(1,2)(3,4) //返回10
防抖與節(jié)流
防抖
function debounce(fn, wait) { var timeout = null; return function() { if(timeout !== null) { clearTimeout(timeout); } timeout = setTimeout(fn, wait); } } // 處理函數(shù) function handle() { console.log(Math.random()); } // 滾動(dòng)事件 window.addEventListener("scroll", debounce(handle, 1000));
節(jié)流
var throttle = function(func, delay) { var prev = 0; return function() { var context = this; var args = arguments; var now = Date.now(); if (now - prev >= delay) { func.apply(context, args); prev = Date.now(); } } } function handle() { console.log(Math.random()); } window.addEventListener("scroll", throttle(handle, 1000));
var throttle = function(func, delay) { var timer = null; return function() { var context = this; var args = arguments; if (!timer) { timer = setTimeout(function() { func.apply(context, args); timer = null; }, delay); } } } function handle() { console.log(Math.random()); } window.addEventListener("scroll", throttle(handle, 1000));
節(jié)流中用時(shí)間戳或定時(shí)器都是可以的。更精確地,可以用時(shí)間戳+定時(shí)器,當(dāng)?shù)谝淮斡|發(fā)事件時(shí)馬上執(zhí)行事件處理函數(shù),最后一次觸發(fā)事件后也還會(huì)執(zhí)行一次事件處理函數(shù)。
var throttle = function(func, delay) { var timer = null; var startTime = 0; return function() { var curTime = Date.now(); var remaining = delay - (curTime - startTime); var context = this; var args = arguments; clearTimeout(timer); if (remaining <= 0) { func.apply(context, args); startTime = Date.now(); } else { timer = setTimeout(func, remaining); } } } function handle() { console.log(Math.random()); } window.addEventListener("scroll", throttle(handle, 1000));
模擬new
new產(chǎn)生的實(shí)例可以訪問(wèn)Constructor里的屬性,也可以訪問(wèn)到Constructor.prototype中的屬性,前者可以通過(guò)apply來(lái)實(shí)現(xiàn),后者可以通過(guò)將實(shí)例的proto屬性指向構(gòu)造函數(shù)的prototype來(lái)實(shí)現(xiàn)
我們還需要判斷返回的值是不是一個(gè)對(duì)象,如果是一個(gè)對(duì)象,我們就返回這個(gè)對(duì)象,如果沒(méi)有,我們?cè)摲祷厥裁淳头祷厥裁?/p>
function New(){ var obj=new Object(); //取出第一個(gè)參數(shù),就是我們要傳入的構(gòu)造函數(shù);此外因?yàn)閟hift會(huì)修改原數(shù)組,所以arguments會(huì)被去除第一個(gè)參數(shù) Constructor=[].shift.call(arguments); //將obj的原型指向構(gòu)造函數(shù),這樣obj就可以訪問(wèn)到構(gòu)造函數(shù)原型中的屬性 obj._proto_=Constructor.prototype; //使用apply改變構(gòu)造函數(shù)this的指向到新建的對(duì)象,這樣obj就可以訪問(wèn)到構(gòu)造函數(shù)中的屬性 var ret=Constructor.apply(obj,arguments); //要返回obj return typeof ret === "object" ? ret:obj; }
function Otaku(name,age){ this.name=name; this.age=age; this.habit="Games" } Otaku.prototype.sayYourName=function(){ console.log("I am" + this.name); } var person=objectFactory(Otaku,"Kevin","18") console.log(person.name)//Kevin console.log(person.habit)//Games console.log(person.strength)//60
模擬call
call()方法在使用一個(gè)指定的this值和若干個(gè)指定的參數(shù)值的前提下調(diào)用某個(gè)函數(shù)或方法
模擬的步驟是:將函數(shù)設(shè)為對(duì)象的屬性—>執(zhí)行該函數(shù)—>刪除該函數(shù)
this參數(shù)可以傳null,當(dāng)為null的時(shí)候,視為指向window
函數(shù)是可以有返回值的
簡(jiǎn)單版
var foo = { value: 1, bar: function() { console.log(this.value) } } foo.bar() // 1
完善版
Function.prototype.call2 = function(context) { var context=context||window context.fn = this; let args = [...arguments].slice(1); let result = context.fn(...args); delete context.fn; return result; } let foo = { value: 1 } function bar(name, age) { console.log(name) console.log(age) console.log(this.value); } //表示bar函數(shù)的執(zhí)行環(huán)境是foo,即bar函數(shù)里面的this代表foo,this.value相當(dāng)于foo.value,然后給bar函數(shù)傳遞兩個(gè)參數(shù) bar.call2(foo, "black", "18") // black 18 1
模擬apply
apply()的實(shí)現(xiàn)和call()類(lèi)似,只是參數(shù)形式不同
Function.prototype.apply2 = function(context = window) { context.fn = this let result; // 判斷是否有第二個(gè)參數(shù) if(arguments[1]) { result = context.fn(...arguments[1]) } else { result = context.fn() } delete context.fn return result }
模擬bind
Function.prototype.bind2=function(context){ var self=thisl var args=Array.prototype.slice.call(arguments,1); var fNOP=function(){}; var fBound=function(){ var bindArgs=Array.prototype.slice.call(arguments); return self.apply(this instanceof fNOP ? this : context, args.concat(bindAt)) } }
模擬instanceof
function instanceOf(left,right) { let proto = left.__proto__; let prototype = right.prototype while(true) { if(proto === null) return false if(proto === prototype) return true proto = proto.__proto__; } }
模擬JSON.stringify
JSON.stringify(value[, replacer [, space]])
Boolean | Number| String 類(lèi)型會(huì)自動(dòng)轉(zhuǎn)換成對(duì)應(yīng)的原始值。
undefined、任意函數(shù)以及symbol,會(huì)被忽略(出現(xiàn)在非數(shù)組對(duì)象的屬性值中時(shí)),或者被轉(zhuǎn)換成 null(出現(xiàn)在數(shù)組中時(shí))。
不可枚舉的屬性會(huì)被忽略
如果一個(gè)對(duì)象的屬性值通過(guò)某種間接的方式指回該對(duì)象本身,即循環(huán)引用,屬性也會(huì)被忽略。
function jsonStringify(obj) { let type = typeof obj; if (type !== "object") { if (/string|undefined|function/.test(type)) { obj = """ + obj + """; } return String(obj); } else { let json = [] let arr = Array.isArray(obj) for (let k in obj) { let v = obj[k]; let type = typeof v; if (/string|undefined|function/.test(type)) { v = """ + v + """; } else if (type === "object") { v = jsonStringify(v); } json.push((arr ? "" : """ + k + "":") + String(v)); } return (arr ? "[" : "{") + String(json) + (arr ? "]" : "}") } } jsonStringify({x : 5}) // "{"x":5}" jsonStringify([1, "false", false]) // "[1,"false",false]" jsonStringify({b: undefined}) // "{"b":"undefined"}"
模擬JSON.parse
JSON.parse(text[, reviver])
用來(lái)解析JSON字符串,構(gòu)造由字符串描述的JavaScript值或?qū)ο蟆L峁┛蛇x的reviver函數(shù)用以在返回之前對(duì)所得到的對(duì)象執(zhí)行變換(操作)。
利用eval
function jsonParse(opt) { return eval("(" + opt + ")"); } jsonParse(jsonStringify({x : 5})) // Object { x: 5} jsonParse(jsonStringify([1, "false", false])) // [1, "false", falsr] jsonParse(jsonStringify({b: undefined})) // Object { b: "undefined"}
避免在不必要的情況下使用 eval,eval() 是一個(gè)危險(xiǎn)的函數(shù), 他執(zhí)行的代碼擁有著執(zhí)行者的權(quán)利。如果你用 eval()運(yùn)行的字符串代碼被惡意方(不懷好意的人)操控修改,您最終可能會(huì)在您的網(wǎng)頁(yè)/擴(kuò)展程序的權(quán)限下,在用戶(hù)計(jì)算機(jī)上運(yùn)行惡意代碼
利用new Function()
Function與eval有相同的字符串參數(shù)特性,eval 與 Function 都有著動(dòng)態(tài)編譯js代碼的作用,但是在實(shí)際的編程中并不推薦使用。
var func = new Function(arg1, arg2, ..., functionBody)
var jsonStr = "{ "age": 20, "name": "jack" }" var json = (new Function("return " + jsonStr))();
創(chuàng)建對(duì)象
創(chuàng)建自定義對(duì)象最簡(jiǎn)單的方式就是創(chuàng)建一個(gè)Object的實(shí)例,然后再為它添加屬性和方法,早期的開(kāi)發(fā)人員經(jīng)常使用這種模式來(lái)創(chuàng)建對(duì)象,后來(lái)對(duì)象字面量的方法成了創(chuàng)建對(duì)象的首選模式。雖然object構(gòu)造函數(shù)或者對(duì)象字面量的方法都可以用來(lái)創(chuàng)建對(duì)象,但是這些方法使用同一個(gè)接口創(chuàng)建很多對(duì)象,會(huì)產(chǎn)生大量的重復(fù)代碼。為了解決這個(gè)問(wèn)題,人們開(kāi)始使用各種模式來(lái)創(chuàng)建對(duì)象,在這些模式中,一般推薦使用四種方式,包括構(gòu)造函數(shù)模式、原型模式、構(gòu)造函數(shù)和原型組合模式,動(dòng)態(tài)原型模式,其他的方式,包括工廠模式、寄生構(gòu)造函數(shù)模式、穩(wěn)妥構(gòu)造函數(shù)模式平時(shí)使用的較少。而這些方式中,用的最多最推薦的應(yīng)是組合模式和動(dòng)態(tài)原型模式
構(gòu)造函數(shù)和原型組合模式
優(yōu)點(diǎn):
解決了原型模式對(duì)于引用對(duì)象的缺點(diǎn)
解決了原型模式?jīng)]有辦法傳遞參數(shù)的缺點(diǎn)
解決了構(gòu)造函數(shù)模式不能共享方法的缺點(diǎn)
function Person(name) { this.name = name this.friends = ["lilei"] } Person.prototype.say = function() { console.log(this.name) } var person1 = new Person("hanmeimei") person1.say() //hanmeimei
動(dòng)態(tài)原型模式
優(yōu)點(diǎn):
可以在初次調(diào)用構(gòu)造函數(shù)的時(shí)候就完成原型對(duì)象的修改
修改能體現(xiàn)在所有的實(shí)例中
function Person(name) { this.name = name // 檢測(cè)say 是不是一個(gè)函數(shù) // 實(shí)際上只在當(dāng)前第一次時(shí)候沒(méi)有創(chuàng)建的時(shí)候在原型上添加sayName方法 //因?yàn)闃?gòu)造函數(shù)執(zhí)行時(shí),里面的代碼都會(huì)執(zhí)行一遍,而原型有一個(gè)就行,不用每次都重復(fù),所以?xún)H在第一執(zhí)行時(shí)生成一個(gè)原型,后面執(zhí)行就不必在生成,所以就不會(huì)執(zhí)行if包裹的函數(shù), //其次為什么不能再使用字面量的寫(xiě)法,我們都知道,使用構(gòu)造函數(shù)其實(shí)是把new出來(lái)的對(duì)象作用域綁定在構(gòu)造函數(shù)上,而字面量的寫(xiě)法,會(huì)重新生成一個(gè)新對(duì)象,就切斷了兩者的聯(lián)系! if(typeof this.say != "function") { Person.prototype.say = function( alert(this.name) } }
后記:
具體的一些代碼實(shí)現(xiàn)請(qǐng)前往github項(xiàng)目主頁(yè),如果大家覺(jué)得對(duì)你有幫助的話,請(qǐng)fork一下這個(gè)項(xiàng)目,搬磚不易,后期的關(guān)于JavaScript,node和框架的源代碼實(shí)現(xiàn)都會(huì)在github上更新,感謝你的閱讀。
參考資料:
冴羽的JavaScript專(zhuān)題系列
「中高級(jí)前端面試」JavaScript手寫(xiě)代碼無(wú)敵秘籍
前端筆試之手寫(xiě)代碼(一)
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/6651.html
摘要:另外回答的時(shí)候要淡定,一些問(wèn)題就算不懂也不能慌,要和面試官談笑風(fēng)生,然后盡量扯回到自己懂的東西上面大公司比如百度給我的感覺(jué)就是很重視基礎(chǔ)思維和潛力。 —— 雖然我的offer少,但是我的拒信多啊 這幾天終于閑下來(lái),做一點(diǎn)微小的工作,整理了一些之前幾家公司的前端面試題和個(gè)人經(jīng)驗(yàn),想做前端的師弟妹可以參考,也歡迎各同行大神來(lái)指教~ (以下問(wèn)題不分先后,時(shí)間久遠(yuǎn)難免有些遺漏;很多問(wèn)題面試官都...
摘要:另外回答的時(shí)候要淡定,一些問(wèn)題就算不懂也不能慌,要和面試官談笑風(fēng)生,然后盡量扯回到自己懂的東西上面大公司比如百度給我的感覺(jué)就是很重視基礎(chǔ)思維和潛力。 —— 雖然我的offer少,但是我的拒信多啊 這幾天終于閑下來(lái),做一點(diǎn)微小的工作,整理了一些之前幾家公司的前端面試題和個(gè)人經(jīng)驗(yàn),想做前端的師弟妹可以參考,也歡迎各同行大神來(lái)指教~ (以下問(wèn)題不分先后,時(shí)間久遠(yuǎn)難免有些遺漏;很多問(wèn)題面試官都...
摘要:另外回答的時(shí)候要淡定,一些問(wèn)題就算不懂也不能慌,要和面試官談笑風(fēng)生,然后盡量扯回到自己懂的東西上面大公司比如百度給我的感覺(jué)就是很重視基礎(chǔ)思維和潛力。 —— 雖然我的offer少,但是我的拒信多啊 這幾天終于閑下來(lái),做一點(diǎn)微小的工作,整理了一些之前幾家公司的前端面試題和個(gè)人經(jīng)驗(yàn),想做前端的師弟妹可以參考,也歡迎各同行大神來(lái)指教~ (以下問(wèn)題不分先后,時(shí)間久遠(yuǎn)難免有些遺漏;很多問(wèn)題面試官都...
摘要:只有動(dòng)手,你才能真的理解作者的構(gòu)思的巧妙只有動(dòng)手,你才能真正掌握一門(mén)技術(shù)持續(xù)更新中項(xiàng)目地址求求求源碼系列跟一起學(xué)如何寫(xiě)函數(shù)庫(kù)中高級(jí)前端面試手寫(xiě)代碼無(wú)敵秘籍如何用不到行代碼寫(xiě)一款屬于自己的類(lèi)庫(kù)原理講解實(shí)現(xiàn)一個(gè)對(duì)象遵循規(guī)范實(shí)戰(zhàn)手摸手,帶你用擼 Do it yourself!!! 只有動(dòng)手,你才能真的理解作者的構(gòu)思的巧妙 只有動(dòng)手,你才能真正掌握一門(mén)技術(shù) 持續(xù)更新中…… 項(xiàng)目地址 https...
閱讀 3812·2021-11-24 09:39
閱讀 1946·2021-11-16 11:45
閱讀 663·2021-11-16 11:45
閱讀 1128·2021-10-11 10:58
閱讀 2564·2021-09-09 11:51
閱讀 1993·2019-08-30 15:54
閱讀 754·2019-08-29 13:13
閱讀 3516·2019-08-26 12:18