bind()
方法创建一个新的函数,在bind()
被调用时,这个新函数的this
被指定为bind()
的第一个参数,而其余参数将作为新函数的参数,供调用时使用。 --MDN
简单说,bind
和call/apply
类似都也是改变this
的指向。但是bind
并不会立即执行函数,而是返回一个绑定了this
的新函数,且新函数的this
无法再次被修改。
举个例子吧:
let obj = {
num:1,
add : function (a,b) {
return a+b+this.num;
}
}
console.log(obj.add(1,2));//4
let plus = obj.add;
// 原因:this.num在当前作用域内不存在,this指向window
console.log(plus(1,2));//NaN
// 使用call/apply改变this的指向
console.log(plus.call(obj, 1,2)); //4
console.log(plus.apply(obj, [1, 2]));//4
//bind返回一个新函数
let res = plus.bind(obj,1,2);
console.log(res());//4
先通过一个例子来看一下bind
都做了什么
var obj = {name:"Smiley"};
var greeting = function(str, lang){
this.value = 'greetingValue';
console.log("Welcome "+this.name+" to "+str+" in "+lang);
};
var objGreeting = greeting.bind(obj, 'the world');
objGreeting('JS')
bind
改变了greeting
当中this
的指向,使得this
指向了obj
,因此,this.name
的内容是Smiley
。最后,bind
会返回一个函数。bind
的时候,就可以开始给greeting
传递参数。上面的例子当中,我们把’the world’
作为greeting
的第一个参数。objGreeting
这个函数的时候,再传入剩余的参数。上面的例子中,第二个参数是’JS’作为第二个参数lang。MDN
中提到的:“bind()
函数会创建一个新绑定函数(bound function,BF)。绑定函数也可以使用new
运算符构造,提供的this
值会被忽略,但前置参数仍会提供给模拟函数”。有点晦涩,这也是bind
实现中最复杂的一步,使用new
关键字这种情况我们一会儿再分析。接下来我们实现bind:
Function.prototype._bind = function(oThis){
if(typeof this !== 'function'){
throw new TypeError('被绑定的对象需要是函数');
}
const self = this;
// 将类数组对象转换成数组并截取
const args = [].slice.call(arguments, 1);
let func = function(){};
let fBound = function(){
// instanceof用来检测某个实例对象的原型链上是否存在这个构造函数的prototype属性,this instanceof func === true时,
//说明返回的fBound被当做new的构造函数调用,此时this=fBound(){},否则this=window,
//如果是的话使用新创建的this代替硬绑定的this
return self.apply(this instanceof func ? this : oThis, args.concat([].slice.call(arguments)));
}
//维护原型关系
if(this.prototype){
func.prototype = this.prototype;
}
//使fBound.prototype是func的实例,返回的fBound若作为new的构造函数,新对象的__proto__就是func的实例
fBound.prototype = new func();
return fBound;
}