觀感度:🌟🌟🌟🌟🌟前端
口味:蟹黃豆腐git
烹飪時間:5mingithub
本文已收錄在前端食堂同名倉庫
Github
github.com/Geekhyt,歡迎光臨食堂,若是以爲酒菜還算可口,賞個 Star 對食堂老闆來講是莫大的鼓勵。
從略帶銀絲的頭髮和乾淨利落的步伐我察覺到,面前坐着的這個面試官有點深不可測。我像往常同樣,準備花 3 分鐘的時間給面試官來一套昨天晚上精心準備的自我介紹。我自信且得意的訴說着對過往項目所付出的心血,所作的優化取得了怎樣的成果,爲公司提升了多少的收入。。。面試
顯然,面試官對我說的數字很感興趣,嘴角微微上揚,通過了一番細節的探討和技術的對線後。面試官拿出了一張紙。數組
手寫代碼。app
注重基礎的面試官是靠譜的,爲了征服他,我一邊講解着實現原理一邊寫出了代碼。函數
call 和 apply 的區別:call 方法接收的是一個參數列表,apply 方法接收的是一個包含多個參數的數組。
優化
context
存在就使用 context
,不然是 window
Object(context)
將 context
轉換成對象,並經過 context.fn
將 this
指向 context
1
開始,第 0
個是上下文,後面纔是咱們須要的參數push
進 args
toString
方法,這樣能夠實現將參數一個個傳入,並經過 eval
執行fn
Function.prototype.call = function(context) { context = context ? Object(context) : window; context.fn = this; let args = []; for (let i = 1; i < arguments.length; i++) { args.push('arguments['+ i +']'); } let res = eval('context.fn('+ args +')'); delete context.fn; return res; }
apply
無需循環參數列表,傳入的 args
就是數組args
是可選參數,若是不傳入的話,直接執行Function.prototype.apply = function(context, args) { context = context ? Object(context) : window; context.fn = this; if (!args) { return context.fn(); } let res = eval('context.fn('+ args +')'); delete context.fn; return res; }
bind
的參數能夠在綁定和調用的時候分兩次傳入bindArgs
是綁定時除了第一個參數之外傳入的參數,args
是調用時候傳入的參數,將兩者拼接後一塊兒傳入new
運算符構造綁定函數,則會改變 this
指向,this
指向當前的實例Fn
連接原型,這樣 fBound
就能夠經過原型鏈訪問父類 Fn
的屬性Function.prototype.bind = function(context) { let that = this; let bindArgs = Array.prototype.slice.call(arguments, 1); function Fn () {}; function fBound(params) { let args = Array.prototype.slice.call(arguments) ; return that.apply(this instanceof fBound ? this : context, bindArgs.concat(args)); } Fn.prototype = this.prototype; fBound.prototype = new Fn(); return fBound; }
Constructor
就是 new
時傳入的第一個參數,剩餘的 arguments
是其餘的參數obj.__proto__ = Constructor.prototype
繼承原型上的方法arguments
傳給 Contructor
,綁定 this
指向爲 obj
,並執行obj
const myNew = function() { let Constructor = Array.prototype.shift.call(arguments); let obj = {}; obj.__proto__ = Constructor.prototype; let res = Constructor.apply(obj, arguments); return res instanceof Object ? res : obj; }
left
的原型鏈中層層查找,是否有原型等於 prototype
left === null
,即找到頭沒找到返回 false
,right === left
,即找到返回 true
left = left.__proto__
,不停的向上查找const myInstanceof = function(left, right) { right = right.prototype; left = left.__proto__; while (true) { if (left === null) { return false; } if (right === left) { return true; } left = left.__proto__; } }
F
,而後讓 F.prototype
指向 obj
,最後返回 F
的實例const myCreate = function (obj) { function F() {}; F.prototype = obj; return new F(); }