在讀這篇文章以前,但願你對Function.prototype.bind
有所瞭解。git
若是尚未的話,強烈推薦去看看MDN上關於它的介紹,飛機票。github
主要有如下兩個特徵:chrome
MDN上爲了向下兼容給出了bind的polyfill,先把代碼貼出來:bash
if (!Function.prototype.bind) {
Function.prototype.bind = function(oThis) {
if (typeof this !== 'function') {
// closest thing possible to the ECMAScript 5
// internal IsCallable function
throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable');
}
var aArgs = Array.prototype.slice.call(arguments, 1),
fToBind = this,
fNOP = function() {},
fBound = function() {
return fToBind.apply(this instanceof fNOP
? this
: oThis,
aArgs.concat(Array.prototype.slice.call(arguments)));
};
if (this.prototype) {
// Function.prototype does not have a prototype property
fNOP.prototype = this.prototype;
}
fBound.prototype = new fNOP();
return fBound;
};
}
複製代碼
var o1 = { a: 1 }
var o2 = { b: 2 }
var f = function () {
console.log(this)
console.log([].slice.call(arguments))
}
var f1 = f.bind(o1, 1, 2) // A行
var f2 = f1.bind(o2, 3, 4) // B行
f2(5, 6) // C行
複製代碼
學習方法有正向也有反向,咱們從運行代碼來解釋這段polyfill閉包
接下來將會從執行上下文棧來解析這段代碼運行的整個過程。 若是對「執行上下文棧」還不瞭解的話,推薦看個人另外一篇文章——執行上下文app
C行其實會執行兩次函數:函數
第一次:工具
f2(5, 6) === return f1.apply(o2, [3, 4, 5, 6])
複製代碼
第二次:學習
return f1.apply(o2, [3, 4, 5, 6]) === return f.apply(o1, [1, 2, 3, 4, 5, 6]
複製代碼
因此f2(5, 6)的打印的結果就是ui
{a: 1}
[1, 2, 3, 4, 5, 6]
複製代碼
能夠直接放到chrome的開發者工具裏運行獲得結果。
這裏使用的是「原型式繼承」,能夠參考個人另外一篇文章——類相關。
在這裏的做用是,把原函數(f)的原型保留下來,以供第二個亮點使用。
我想你必定很疑惑fBound裏的這段代碼
this instanceof fNOP ? this : oThis
複製代碼
其實這裏的做用就是爲了bind返回的函數不影響new操做符建立對象(也就是this被忽略)。
若是再執行如下語句,再上門的基礎上修改f:
var f = function () {
this.c = 3
console.log(this)
console.log([].slice.call(arguments))
}
var f2Obj = new f2(5, 6);
// 運行過程,下面的this指將要建立的新對象:
f2(5, 6) === return f1.apply(this, [3, 4, 5, 6] === return f.apply(this, [1, 2, 3, 4, 5, 6]
// 結果(在chrome上執行)
打印:
f {c: 3}
[1, 2, 3, 4, 5, 6]
而且 f2Obj.c === 3
複製代碼
不禁得感嘆這個polyfill的做者,思惟太縝密了。我只能經過解析執行上下文一步一步來了解整個設計思路。
謝謝你能看到這裏。
原文摘自個人我的博客,歡迎進來踩踩。