官方解释:
The bind() method creates a new function that, when called, has its this keyword set to the provided value, with a given sequence of arguments preceding any provided when the new function is called.
翻译过来也就是:
该 bind()
方法创建一个新函数,该新函数在被调用时将其 this
关键字设置为提供的值,并在调用新函数时提供给定的参数序列之前。
我们都知道,bind
和 call/apply
一样,都是用来改变上下文 this
指向的,不同的是,call/apply
是直接使用在函数上,而 bind
绑定 this
后返回一个函数(闭包)
刚说完 bind
是返回一个函数,它的执行很像函数柯里化的一个过程,如下:
fuction fn1(x){ // 柯里化函数
return function(y){
return x + y
}
}
fn1(1)(2) // 3
function fn2(a,b){ // bind
return a + b
}
fn2.bind(null, 1)(2) // 3
复制代码
这里是 bind
的一个特殊用法,预设参数。只要将这些参数(如果有的话)作为bind()
的参数写在this后面。
当绑定函数被调用时,这些参数会被插入到目标函数的参数列表的开始位置,传递给绑定函数的参数会跟在它们后面。如下:
function sum (a,b) {
return a + b
}
let add1 = sum.bind(null, 12)
let result = add1(5) // result = 17
result = add1(6, 3) // result = 18 注意第二个3被丢弃了
复制代码
下面开始解析,在解析前先看如下一题:
function f() {
console.log(this);
}
let f1 = f.bind(1).bind(2);
f1(); // this => 1
复制代码
拆分步骤就等同与下面:
let case = f.bind(1);
let f1 = case.bind(2);
f1();
复制代码
case
是 f.bind(1)
的执行结果,这里改变的是 f
的this
。即:
case = fuction(){
f.apply(1);
}
复制代码
同理,f1
执行结果,改变的是 case
的 this
指向
f1 = function () {
case.apply(2);
}
复制代码
重点:
f1()
执行的时候改变的是case
的this
,而不是f
的this
。即
f1()
的时候是调用case.apply(2)
,通过case.apply(2)
再去调用f.apply(2)
。所以不论中间有多少层bind
,最后那个f
调用永远都是最开始的1
。
如下:
let case = f.bind(1);
let f1 = case.bind(2);
let f2 = f1.bind(3);
let f3 = f2.bind(4);
let f4 = f3.bind(5);
let f5 = f4.bind(6);
f5();
f5() => f4.apply(6) => f3.bind(5) => f2.bind(4) => f1.bind(3) => case.bind(2) => f.bind(1)
复制代码
bind基本实现原理[传递一个参数]
Function.prototype.bind = function(context){
let _this = this;
return function(){
_this.apply(context, arguments)
}
}
复制代码
修改一下:bind基本实现原理[传递多个参数]
Function.prototype.bind = function(context){
let _this = this;
// 把方法的参数截取出来
let args = [].slice.call(arguments, 1);
return function(){
// 预设参数一定是 args 在前拼接
_this.apply(context, args.concat([].slice.call(arguments)))
}
}
复制代码