概述
在ECMA-262第五版引入了bind()方法,该方法创建一个新函数。
语法
fn.bind(context[, arg1[, arg2[, ...]]])
第一个参数context将成为返回的新函数的this对象
第二个及以后的参数加上绑定函数运行时本身的参数按照顺序,将作为新函数的擦书
实现原理
Function.prototype.bind = function (context) {
// 调用Array的方法来切割伪数组对象arguments
// 由此获此bing()方法传进来的第二个及以后的参数
var args = Array.prototype.slice.call(arguments, 1);
return function () {
return this.apply(context, args.concat(Array.prototype.slice.call(arguments)));
};
};
其核心思想就是返回一个函数,函数里是通过用apply指定this值的原函数的返回值。
常见应用场景
- 改变对象方法里this的值
var ob = {
name: 'joe',
getName: function () {
alert(this.name);
}
};
// 改变getName方法里原本的this对象为新对象{name: 'haha'}
var app = ob.getName.bind({name: 'haha'});
app();
- 改变事件处理函数里的this值,因为在事件处理函数中的this指向的是dom元素,在某些情况下我们需要改变这个this值
$(function () {
// 这里的e是定义为原函数里的参数,但是返回的新函数没有定义参数
// 因此相当于function(e) {}
$('.btn').on('click', function(e) {
alert(this.name);
}.bind({name: 'joe'}));
});
多次绑定bind方法
那么你有没有想过,如果使用bind()方法多次绑定,最终得到的this会是哪个绑定的呢?
function say() {
alert(this.x);
};
var a = say.bind({x: 1});
var b = a.bind({x: 2});
b(); // 这里会输出1还是2呢?
这里我对这手机想了好久也没绕出来,最后代码一些就明白了。。。那你想到结果了吗?
那么我们不妨先分析一下
say函数使用bind方法,穿进去了一个对象,相当于
var a = function() {
return say.apply({x: 1});
};
如果我们对得到的函数a再进行绑定,则相当于
var b = function() {
return a.apply({x: 2});
};
即
var b = function() {
return function() {
return say.apply({x: 1});
}.apply({x: 2});
};
这样虽然我们改变了函数a里this的值,但是最后函数say里的this的值还是由第一次绑定时的参数决定,而与函数a中的this值无关
多次绑定的结果
所以无论使用bind绑定多少次,最终原函数的this值是由第一次绑定传的参数决定的。
多次绑定参数的顺序
function say() {
alert(this.x);
};
var a = say.bind({x: 1},1,2,3);
var b = a.bind({x: 2},4,5,6);
a(7,8,9);
b(7,8,9);
// 此时原函数say参数的顺序的怎样的呢?
// 是[4,5,6,1,2,3,7,8,9]还是[1,2,3,4,5,6,7,8,9]
首先对say使用bind方法,会改变函数say的this值,和
“内置”参数。所以
a(7,8,9)
的参数组成是:
内置的参数 + 调用时传入的参数 = 最终函数,即[1,2,3]+ [7,8,9] = [1,2,3,7,8,9]
而对函数a使用bind方法,只会改变函数a的this值,和往函数a里
“内置”参数。所以
b(7,8,9)
的参数组成是:[1,2,3](在函数say内置的参数) + [4,5,6](在函数a内置的参数) + [7,8,9] = [1,2,3,4,5,6,7,8,9]
总结
对哪个函数使用bind()方法即改变这个函数的this值,和内置其参数,或者说像克里化一样理解,先预置好参数
var a = say.bind({x:1},1,2,3); // 是改变函数say的this值,和在函数say上预置参数1,2,3
var b = a.bind({x: 2}, 4,5,6); // 是改变函数a的this,和在函数a上预置预置参数4,5,6