在读这篇文章以前,但愿你对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的做者,思惟太缜密了。我只能经过解析执行上下文一步一步来了解整个设计思路。
谢谢你能看到这里。
原文摘自个人我的博客,欢迎进来踩踩。