MDN上的解释是: bind()函数会创建一个新绑定函数,当绑定函数被调用时,会以bind()的第一个参数作为运行时的this,之后的一系列参数加上绑定函数运行时本身的参数按顺序作为原函数的参数。
1.bind方法绑定对象,并且返回一个函数
var module = {
x: 42,
getX: function() {
return this.x;
}
}
var unboundGetX = module.getX;
console.log(unboundGetX()); // 此时的this指的是window
// undefined
var boundGetX = unboundGetX.bind(module);
console.log(boundGetX());
// expected output: 42
在上面代码里, 通过bind()方法创建了一个绑定函数之后,它被执行时,它的this会被设置成module, 所以第二个输出为module.x的值42.
我们可以简单的模拟实现:
Function.prototype.bind2 = function(context){
var self = this; // 保存this,即调用bind方法的目标函数
return function () {
return self.apply(context);
}
}
2.bind()方法支持在绑定的时候传参数
function list() {
return Array.prototype.slice.call(arguments);
}
function addArguments(arg1, arg2) {
return arg1 + arg2;
}
var bindList = list.bind(null, 37);
var result = bindList(1, 2);
console.log(result); // [37, 1, 2]
除了在bind时可以只传部分参数外, 还可以在执行返回函数时再接着传参数(即函数柯里化)。我们可以通过arguments来解决:
Function.prototype.bind2 = function(context){
var self = this, // 保存this,即调用bind方法的目标函数
args = Array.prototype.slice.call(arguments, 1); // 获取第二个参数到最后一个参数
return function () {
var innerArgs = Array.prototype.slice.call(arguments); // 获取的是bind返回的函数传入的参数
var finalArgs = args.concat(innerArgs); // 按照顺序拼接起来
return self.apply(context, finalArgs);
}
}
当然我们可以采用es6:
Function.prototype.bind2 = function(context) {
var self= this;
var args = [...arguments].slice(1);
// 返回一个函数
return function () {
return self.apply(context, args.concat(...arguments));
}
}
3.作为构造函数使用的绑定函数
MDN上说明: 绑定函数自动适应于使用 new 操作符去构造一个由目标函数创建的新实例。当一个绑定函数是用来构建一个值的,原来提供的 this 就会被忽略。不过提供的参数列表仍然会插入到构造函数调用时的参数列表之前。
function Point(x, y) {
this.x = x;
this.y = y;
}
Point.prototype.toString = function() {
return this.x + ',' + this.y;
};
var p = new Point(1, 2);
p.toString(); // '1,2'
var emptyObj = {};
var YAxisPoint = Point.bind(emptyObj, 0);
// 以下这行代码在 polyfill 不支持,
// 在原生的bind方法运行没问题:
//(译注:polyfill的bind方法如果加上把bind的第一个参数,即新绑定的this执行Object()来包装为对象,Object(null)则是{},那么也可以支持)
var YAxisPoint = Point.bind(null, 0);
var axisPoint = new YAxisPoint(5);
axisPoint.toString(); // '0,5'
axisPoint instanceof Point; // true
axisPoint instanceof YAxisPoint; // true
new Point(17, 42) instanceof YAxisPoint; // true
我们可以模拟下(这里注意bind的第一个参数):
Function.prototype.bind2 = function (context) {
var self = this, // 保存this,即调用bind方法的目标函数
args = Array.prototype.slice.call(arguments, 1), // 获取第二个参数到最后一个参数
fn = function() {}, // 作为中转构造函数
bound = function() {
var innerArgs = Array.prototype.slice.call(arguments); // 获取的是bind返回的函数传入的参数
var finalArgs = args.concat(innerArgs); // 按照顺序拼接起来
context = typeof context != 'object' ? Object(context): context; // 简单处理
return self.apply(this instanceof fn ? this : context, finalArgs);
};
fn.prototype = self.protype; // 使绑定后的函数与调用bind()的函数处于同一原型链上
bound.prototype = new fn();
return bound;
}
参考资料: https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Function/bind