Bind:
bind() 方法会创建一个新函数。当这个新函数被调用时,bind() 的第一个参数将作为它运行时的 this,之后的一序列参数将会在传递的实参前传入作为它的参数。(来自于 MDN )
接下来例子结合源码来分析:
//测试
var value = 2;
var foo = {
value: 1
};
function bar(name, age) {
this.habit = 'shopping';
console.log(this.value);
console.log(name);
console.log(age);
}
bar.prototype.friend = 'kevin';
var bindFoo = bar.myBind(foo, 'daisy');
var obj = new bindFoo('18');
// undefined
// daisy
// 18
console.log(obj.habit);
console.log(obj.friend);
// shopping
// kevin
Function.prototype.myBind = function(context, ...args){
// 获取自身的this,也就是 bar
let self = this;
let targetFuc = function(){
// 获取绑定的函数的传参,也就是 '18'
let targetArg = Array.prototype.slice.call(arguments)
// 以例子来看就是将bar的this指向context,也就是fo
// 正常来说是 self.apply(context,args.concat(targetArg)) 就行了
// 但是因为bind的返回可以用new绑定,new会改变this指向:
// 如果bind绑定后的函数被new了,那么this指向会发生改变,指向当前函数的实例。也就是targetFuc
// this instanceof targetFuc 判断返回的函数是否被new绑定在了实例上
// 因为bind()除了this还接收其他参数,bind()返回的函数也接收参数,这两部分的参数都要传给返回的函数
// args.concat(targetArg) 就相当于 ['daisy'].concat(['18])
return self.apply(this instanceof targetFuc ? this: context,args.concat(targetArg))
}
// 修改返回函数的 prototype 为绑定函数的 prototype,实例就可以继承绑定函数的原型中的值,也就是friend和habit
targetFuc.prototype = Object.create(self.prototype);
return targetFuc
}
解释就不多说了,看备注写的很清楚