来自MDN:
bind()方法创建一个新函数,在调用时,将其this关键字设置为提供的值
我很高兴看到它在这个例子中起作用:
(function () {
console.log(this);
}).bind({foo:"bar"})();
记录Object { foo="bar"}
。
但是,如果我链接另一个绑定调用,甚至是"调用"打电话,我仍然使用"这个"分配给传递给第一个绑定的对象。例子:
(function () {
console.log(this);
}).bind({foo:"bar"}).bind({oof:"rab"})();
&安培;
(function () {
console.log(this);
}).bind({foo:"bar"}).call({oof:"rab"});
记录Object { foo="bar"}
而不是我期望的结果:Object { oof="rab"}
。
无论我链接多少个绑定调用,只有第一个看起来有效。
为什么吗
这可能会有所帮助。我刚刚发现jQuery的版本行为方式相同! :o
jQuery.proxy(
jQuery.proxy(function() {
console.log(this);
},{foo:"bar"})
,{oof:"rab"})();
记录Object { foo="bar"}
答案 0 :(得分:43)
很容易将bind
视为修改函数以使用新的this
。在这个(不正确的)解释中,人们认为bind
为函数添加某种魔术标志,告诉它下次调用它时使用不同的this
。如果是这种情况,则应该可以“覆盖”并更改魔术标志。然后人们会问,任意限制这种能力的原因是什么?
但实际上,不它是如何运作的。 bind
创建并返回 new 函数,当调用时,调用具有特定this
的第一个函数。创建函数时,此新创建的函数(使用指定的this
调用原始函数)的行为在中刻录。它不能被更改,因为函数返回的任何其他函数的内部结构都可以在事后更改。
查看bind
:
// NOT the real bind; just an example
Function.prototype.bind = function(ctxt) {
var fn = this;
return function bound_fn() {
return fn.apply(ctxt, arguments);
};
}
my_bound_fn = original_fn.bind(obj);
如您所见,bound_fn
中没有任何地方,bind
返回的函数,它是指引用绑定函数的this
。它被忽略了,所以
my_bound_fn.call(999, arg) // 999 is ignored
或
obj = { fn: function () { console.log(this); } };
obj.fn = obj.fn.bind(other_obj);
obj.fn(); // outputs other_obj; obj is ignored
所以我可以再次绑定从bind
“返回的函数”,但这是不重新绑定原始函数;它只是绑定外部函数,它对内部函数没有影响,因为它已经设置为调用底层函数,并将上下文(this
值)传递给bind
。我可以一次又一次地绑定但是我最终做的就是创建更多外部函数,这些函数可能绑定到某些东西但最终仍然调用从第一个bind
返回的最内层函数。
因此,说“bind
”不能被覆盖有点误导。
如果我想“重新绑定”一个函数,那么我可以对原始函数进行新的绑定。所以如果我绑定它一次:
function orig() { }
my_bound_fn = orig.bind(my_obj);
然后我想安排我的原始函数与其他this
一起调用,然后我不重新绑定绑定函数:
my_bound_fn = my_bound_fn.bind(my_other_obj); // No effect
相反,我只是创建一个绑定到原始函数的新函数:
my_other_bound_fn = orig.bind(my_other_obj);
答案 1 :(得分:12)
我在MDN上找到了这一行:
bind()函数用。创建一个新函数(一个绑定函数) 相同的函数体(ECMAScript 5术语中的内部调用属性)as 它被调用的函数(绑定函数的目标 函数)将此值绑定到bind()的第一个参数, 无法覆盖。
所以也许它一旦确定就无法覆盖。
答案 2 :(得分:5)
例如,
function original_fn() {
document.writeln(JSON.stringify(this));
}
Function.prototype.rebind = function(obj) {
var fn = this;
var bound = function func() {
fn.call(func.receiver, arguments);
};
bound.receiver = obj;
bound.rebind = function(obj) {
this.receiver = obj;
return this;
};
return bound;
}
var bound_fn = original_fn.rebind({foo: 'bar'});
bound_fn();
var rebound_fn = bound_fn.rebind({fred: 'barney'});
rebound_fn();

或者,node.js的输出如下。
{ foo: 'bar' }
{ fred: 'barney' }
请注意,对rebind
的第一次调用是调用添加到Function.prototype
的那个,因为它是在普通函数original_fn
上调用的,但第二次调用是调用rebind
1}}作为属性添加到绑定函数(并且任何后续调用也将调用此函数)。 rebind
只更新receiver
并返回相同的函数对象。
通过将命名的函数表达式设置为绑定函数,可以访问receiver
属性。
答案 3 :(得分:3)
好的,这主要是猜测,但我会尝试通过它。
ECMAScript规范(当前已关闭)声明bind
函数的以下内容(强调我自己的):
15.3.4.5 Function.prototype.bind(thisArg [,arg1 [,arg2,...]])
bind方法接受一个或多个参数thisArg和(可选) arg1,arg2等,并通过执行返回一个新的函数对象 以下步骤:
- 让Target为此值。
- 如果IsCallable(Target)为false,则抛出TypeError异常。
- 设A是按此顺序在thisArg(arg1,arg2等)之后提供的所有参数值的新(可能为空)内部列表。
- 设F为新的原生ECMAScript对象。
- 按照8.12中的规定设置F的[[Get]]除外的所有内部方法。
- 按照15.3.5.4中的规定设置F的[[Get]]内部属性。
- 将F的[[TargetFunction]]内部属性设置为Target。
- 将F的[[BoundThis]]内部属性设置为thisArg的值。
- 将F的[[BoundArgs]]内部属性设置为A.
- 将F的[[Class]]内部属性设置为"功能"。
- 将F的[[Prototype]]内部属性设置为标准内置函数原型对象,如中所述 15.3.3.1。
- 按照15.3.4.5.1。
中的说明设置F的[[Call]]内部属性- 按照15.3.4.5.2。
中的说明设置F的[[Construct]]内部属性- 按照15.3.4.5.3中的说明设置F的[[HasInstance]]内部属性。
- 如果Target的[[Class]]内部属性为" Function",则a。令L为Target的长度属性减去A的长度。 将F的length属性设置为0或L,以两者为准 大。
- 否则将F的长度属性设置为0。
- 将F长度属性的属性设置为15.3.5.1中指定的值。
- 将F的[[Extensible]]内部属性设置为true。
- 让thrower成为[[ThrowTypeError]]函数Object(13.2.3)。
- 使用参数" caller",PropertyDescriptor {[[Get]]:thrower,[[Set]]:thrower,调用F的[[DefineOwnProperty]]内部方法 [[Enumerable]]:false,[[Configurable]]:false},false。
- 使用参数" arguments",PropertyDescriptor {[[Get]]:thrower,[[Set]]:thrower,调用F的[[DefineOwnProperty]]内部方法 [[Enumerable]]:false,[[Configurable]]:false},false。
- 返回F
醇>
当您在使用function
创建的对象上调用bind
时:
15.3.4.5.1 [[Call]]
当使用bind函数创建的函数对象F的[[Call]]内部方法被调用时 这个值和一个参数列表ExtraArgs,以下步骤是 采取:
- 让boundArgs为F [[BoundArgs]]内部属性的值。
- 设为bound这是F [[BoundThis]]内部属性的值。
- 让target为F的[[TargetFunction]]内部属性的值。
- 让args成为一个新列表,其中包含与列表boundArgs相同的值,顺序相同,后跟与列表相同的值 ExtraArgs的顺序相同。
- 返回调用[[Call]]目标的内部方法的结果,提供boundThis作为此值并提供args作为 参数 强>
醇>
Call指定如何调用每个函数。有点像JavaScript call
:
someFunction.[[call]](thisValue, arguments) {
}
但是,当在绑定函数上使用[[call]]
时,thisValue
将被覆盖[[BoundThis]]
的值。在第二次调用bind
的情况下,您尝试覆盖第一个的thisValue
被[[BoundThis]]
替换,基本上不会对{{1}的值产生任何影响}:
thisValue
您会注意到,如果您尝试使用boundFunction.[[call]](thisValue, arguments) {
thisValue = boundFunction.[[BoundThis]];
}
或call
,那么它们也将无效,因为apply
属性的覆盖尝试将在thisValue
{1}}调用下一个函数。
答案 4 :(得分:0)
这些bind()
如何工作的简化示例更好地解释了它。
以下是函数绑定的结果:
function bound_function() {
function original_function() {
console.log(self);
}
var self = 1;
original_function();
}
bound_function()
如果我们将原始函数包装两次会发生什么:
function bound_function2() {
function bound_function1() {
function original_function() {
console.log(self);
}
var self = 1;
original_function();
}
var self = 2;
bound_function1();
}
bound_function2()
答案 5 :(得分:0)
我认为考虑它的方法是:当你第一次调用bind()时,'这个'调用bind()返回的函数内部是FIXED,给定的值。这是可能的,因为它之前没有被修复,它是未绑定的。但是一旦修复它就无法修复到任何其他东西,因为它不再是不固定的,它不再是变量"。
理论上可能存在相反的操作来绑定被叫" unbind"您可以称之为:
myFunk.bind(something)
.unbind(); // -> has same behavior as original myFunk
名称" bind"表示(伪)变量' this'是绑定的东西,它不是简单地分配一个值,然后可以一次又一次地分配。
什么东西是"绑定"它有一个值,并且该值不能被替换 - 因为它是"绑定"。所以你需要一个unbind()操作来实现这一点。但是因为你可以在某个地方拥有原始功能 没有必要"解开"真。
我同意这种行为可能是令人惊讶和意外的,因此可能容易出错,因为如果你得到一个函数作为参数,似乎没有办法判断你的bind()是否有任何影响。
然而,如果你不太了解这样的函数论证,那么你也不可能知道你可以绑定它的价值是什么,而不会打破它对这个'这个'在里面。
所以bind()操作本身就很危险。重新绑定将是双重危险。所以你最好尽量避免这样做。