https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Function/bind
1.什么是绑定函数?
bind()方法创建一个新的函数,当这个新函数被调用时其this置为提供的值,其参数列表前几项置为创建时指定的参数序列。
- 第一次看到这句话时,没看懂,看了下面的实例,才明白了:
var module = {
x: 42,
getX: function(){
return this.x;
}
};
var unboundGetX = module.getX;
// unboundGetX 虽然得到的是 module.getX 这个函数,但是直接执行 unboundGetX() 函数内的 this 指向全局作用域,而不是 module
console.log('unboundGetX=', unboundGetX()); //输出 unboundGetX= undefined
// 我们希望执行这个函数时,函数内的 this 指向 module,该怎么办?
var boundGetX = module.getX.bind(module);
// 这样得到的函数 boundGetX() 在执行时,this 指向 module
console.log('boundGetX=', boundGetX()); //输出 boundGetX= 42
这个实例说明了 JavaScript 新手经常犯的一个错误:将一个方法从对象中拿出来,然后再调用,希望方法中的 this 是原来的对象。
- 也说明了为什么要 bind():为了绑定 this。 否则 this 的值不确定。
- 从原来的函数和原来的对象创建一个绑定函数,则能很漂亮地解决这个问题。
bind() 最简单的用法是创建一个函数,使这个函数不论怎么调用都有同样的 this 值。
2.如何创建绑定函数?
fun.bind(thisArg[, arg1[, arg2[, …]]])
- thisArg:调用绑定函数时作为 this 参数传递给目标函数的值。
- arg1, arg2, … 当绑定函数被调用时,这些参数将置于实参之前传递给被绑定的方法。
bind() 的结果是什么?或返回值是什么?
- 原函数的副本
- 改造了的原函数副本
- 由指定的this值和初始化参数改造了的原函数副本
绑定函数内部原理解析
bind() 会创建一个新函数:绑定函数。绑定函数与原函数具有相同的函数体。
- 调用绑定函数通常会导致执行原函数。
绑定函数具有以下内部属性:
- [[BoundTargetFunction]] - 绑定的函数对象
- [[BoundThis]] - 在调用绑定函数时始终作为this值传递的值。
- [[BoundArguments]] - 一个值列表,其元素用作对绑定函数的任何调用的第一个参数。
- [[Call]] - 执行与此对象关联的代码。通过函数调用表达式调用。内部方法的参数是一个this值和一个包含通过调用表达式传递给函数的参数列表。
当调用绑定函数时,它调用内部方法 Call(boundThis, args)。其中,boundThis 是[[BoundThis]],args 是[[BoundArguments]],后跟函数调用传递的其他参数。
绑定函数也可以使用 new 运算符构造:这样做就好像已经构造了目标函数一样。提供的this值将被忽略,而前置参数将提供给模拟函数。
3.绑定函数示例
3.1 偏函数
bind() 的另一个用途是使一个函数拥有预设的初始参数。这些参数作为bind()的第二个参数,它们会被插入到目标函数的参数列表的开始位置,传递给绑定函数的参数会跟在它们的后面。
function list() {
return Array.prototype.slice.call(arguments);
}
var list1 = list(1, 2, 3); // [1, 2, 3]
// 创建一个函数:带有预设的开头参数
var leadingList = list.bind(null, 37);
var list2 = leadingList(); // [37]
var list3 = leadingList(1, 2, 3); // [37, 1, 2, 3]
这种通过指定部分参数来产生一个新制定的函数的形式就是偏函数。
3.2 配合 setTimeout
在默认情况下,使用 window.setTimeout() 时,this 关键字会指向 window (或全局)对象。当使用类的方法时,需要 this 引用类的实例,你可能需要显式地把 this 绑定到回调函数以便继续使用实例。
function LateBloomer() {
this.petalCount = Math.ceil(Math.random() * 12) + 1;
}
// 给函数原型添加 bloom 方法,1秒之后执行 declare 方法
LateBloomer.prototype.bloom = function() {
// 这朵美丽的花拥有 2 个花瓣!
window.setTimeout(this.declare.bind(this), 1000);
// 这朵美丽的花拥有 undefined 个花瓣!
// window.setTimeout(this.declare, 1000); //试试不绑定
};
LateBloomer.prototype.declare = function() {
console.log('这朵美丽的花拥有 ' + this.petalCount + ' 个花瓣!');
};
var flower = new LateBloomer();
flower.bloom();
凡是 this 值不确定,且需要指定 this 值的地方,都用 bind() 来解决,对吧?这是我的推论,你可以试试。