ES5 实现 bind 函数如下
Function.prototype.bind = function(that){
var self = this,
args = arguments.length > 1 ? Array.slice(arguments, 1) : null,
F = function(){};
var bound = function(){
var context = that, length = arguments.length;
if (this instanceof bound){
F.prototype = self.prototype;
context = new F;
}
var result = (!args && !length)
? self.call(context)
: self.apply(context, args && length ? args.concat(Array.slice(arguments)) : args || arguments);
return context == that ? result : context;
};
return bound;
}
测试1
var bar = function() {
console.log(this.x)
}
var foo = {
x: 3
}
var func = bar.bind(foo);
func(); // 3
bar 函数绑定foo 中的x 值,然后输出3
bind 函数中最主要的是bound 函数,bound 函数做了哪些事呢?
首先context 存储传入的that 到context 中,判断this instanceof bound ,那什么时候this instanceof bound == true 呢?在测试1中的案例中,this instanceof bound 为false ,打印此时的this 输出Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, frames: Window, …} ,发现是window 对象,因为foo 本身就是在window 对象中。
所以此时直接执行self.call(context) ,返回执行的结果3 ,就是我们测试1中的结果。
那什么时候this instanceof bound == true 呢,而且此时还需要使用空函数F 来获取主函数的prototype ,
答案是实例化,什么时候实例化呢?
测试2
var bar = function() {
console.log(this.x)
}
bar.prototype.name = function(){
this.name = 'name';
}
var foo = {
x: 3
}
var func = bar.bind(foo);
var newFunc = new func; // undefined
newFunc.name(); // name
对bar.bind(foo) 进行实例化,此时因为进行了new 操作,new 操作做了什么呢,参考new操作符里面到底发生了什么?所以此时的this 为新生成的bound {} 对象,constructor 为bound 函数,所以此时this instanceof bound == true
那为什么bar.bind(foo) 把foo 对象传递的时候,没有输出3 而是undefined 呢?也是因为new 操作,当前的上下文已经是新生成的newFunc 函数了。而且当this instanceof bound == true 时,会把bar 的prototype 赋给F 函数,而bound 函数返回的是new F ,所以这时bar 的prototype 也赋给newFunc 了。
我们看看ES6的操作,结果和上述例子是一样的。
var bar = function() {
console.log(this.x)
}
bar.prototype.name = function(){
console.log('name')
}
var foo = {
x: 3
}
var func = bar.bind(foo);
func(); // 3
// 实例化
var newFunc = new func; // undefined
newFunc.name(); // name
总结:
所以bind 函数总共做了哪几件事呢?
- 没有实例化时,将传入对象的参数引用到当前函数,执行当前函数,返回结果
- 实例化时,使用
new操作生成新函数,原函数的prototype赋给新函数,执行新函数,并返回新函数