javascript 函数.prototype.bind
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/7282158/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Function.prototype.bind
提问by Ruslan
I've got pretty interesting question about EcmaScript-5 Function.prototype.bind implementation. Usually when you use bind, you do it this way:
我有一个关于 EcmaScript-5 Function.prototype.bind 实现的非常有趣的问题。通常当你使用 bind 时,你是这样做的:
var myFunction = function() {
alert(this);
}.bind(123);
// will alert 123
myFunction();
Okay so that's cool, but what is suppose to happen when we do this?
好的,这很酷,但是当我们这样做时会发生什么?
// rebind binded function
myFunction = myFunction.bind('foobar');
// will alert... 123!
myFunction();
I understand that it's completely logical behavior in terms of how Function.prototype.bind is implemented (https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/bind). But in real life conditions it's completely useless behavior isn't it? The question is: is it bug or feature? If it's a bug, why it's nowhere mentioned? If it's a feature, why then Google Chrome with native "bind" implementation behaves absolutely the same way?
我知道就 Function.prototype.bind 的实现方式而言,这是完全合乎逻辑的行为(https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/bind)。但在现实生活条件下,这是完全无用的行为,不是吗?问题是:它是错误还是功能?如果它是一个错误,为什么没有提到它?如果它是一项功能,那么为什么带有本机“绑定”实现的 Google Chrome 的行为方式完全相同?
To make it more clear, what in my opinion would make more sense, here is the code snippet that implements Function.prototype.bind a little bit differently:
为了更清楚,在我看来更有意义的是,这里是实现 Function.prototype.bind 的代码片段有点不同:
if (!Function.prototype.bind) {
Function.prototype.bind = function() {
var funcObj = this;
var original = funcObj;
var extraArgs = Array.prototype.slice.call(arguments);
var thisObj = extraArgs.shift();
var func = function() {
var thatObj = thisObj;
return original.apply(thatObj, extraArgs.concat(
Array.prototype.slice.call(
arguments, extraArgs.length
)
));
};
func.bind = function() {
var args = Array.prototype.slice.call(arguments);
return Function.prototype.bind.apply(funcObj, args);
}
return func;
};
}
So now try this:
所以现在试试这个:
// rebind binded function
myFunction = myFunction.bind('foobar');
// will alert... "foobar"
myFunction();
In my opinion, replacing "this" makes more sense...
在我看来,替换“这个”更有意义......
So what do you guys think about it?
那么大家怎么看呢?
采纳答案by Jeff Walden
The precedent for Function.prototype.bind
was the implementation of the idea in various JS frameworks. To the best of my knowledge, none of them allowed this
-binding to be changed by subsequent binding. You might as well ask why none of them allowed this-binding changing, as to ask why ES5 doesn't allow it.
先例Function.prototype.bind
是在各种 JS 框架中实现该想法。据我所知,它们都不允许this
-binding 被后续绑定更改。您可能会问为什么他们都不允许更改 this-binding,或者问为什么 ES5 不允许。
You're not the only person I've heard who thought this odd. Chris Leary, who works on Mozilla's JS engine (as I do), thought it a bit odd, raising the issue on Twitter a couple months ago. And in a somewhat different form, I remember one of the Mozilla Labs hackers questioning if there were some way to "unbind" a function, to extract the target function from it. (If you could do that, you could of course bind it to a different this
, at least if you could also extract the bound arguments list to also pass it along.)
你不是我听说过的唯一一个认为这很奇怪的人。在 Mozilla 的 JS 引擎上工作的 Chris Leary(和我一样)认为这有点奇怪,几个月前在 Twitter 上提出了这个问题。以稍微不同的形式,我记得 Mozilla Labs 的一位黑客质疑是否有某种方法可以“解除绑定”一个函数,从中提取目标函数。(如果你能做到这一点,你当然可以将它绑定到一个不同的this
,至少如果你还可以提取绑定参数列表来传递它。)
I don't remember the issue being discussed when bind
was being specified. However, I wasn't paying particularly close attention to the es-discuss mailing list at the time this stuff was hashed out. That said, I don't believe ES5 was looking to innovate in the area much, just "pave a cowpath", to borrow a phrase.
我不记得在bind
指定时讨论的问题。但是,在讨论这些内容时,我并没有特别关注 es-discuss 邮件列表。也就是说,我不相信 ES5 在该领域寻求太多创新,借用一个短语,只是“铺平道路”。
You might possibly be able to propose some introspective methods to address these concerns to es-discuss, if you wrote a sufficiently detailed proposal. On the other hand, binding is a form of information-hiding mechanism, which would cut against its adoption. It might be worth a try to propose something, if you have time. My guess is the information-hiding concern would block a proposal from being adopted. But that's just a guess that could well be wrong. Only one way to find out...
如果您写了一份足够详细的提案,您或许可以提出一些内省的方法来解决这些问题以进行 es-discuss 讨论。另一方面,绑定是一种信息隐藏机制,会阻碍其采用。如果你有时间,不妨尝试提出一些建议。我的猜测是信息隐藏问题会阻止提案被采纳。但这只是一个猜测,很可能是错误的。只有一种方法可以找出...
回答by Remember Monica
When you bind a function, you ask for a new function that ignores it's own this pseudo argument and calls the original function with a fixed value for this.
当你绑定一个函数时,你需要一个新函数,它忽略它自己的这个伪参数,并用一个固定的值调用原始函数。
Binding this function another time has exactly the same behaviour. If bind would somehow patch in a new this into it, it would have to special case for already-bound-functions.
再次绑定此函数具有完全相同的行为。如果 bind 会以某种方式将新的 this 修补到其中,则它必须对已经绑定的函数进行特殊处理。
In other words, bind works exactly the same on "normal" functions as it works on functions returned by bind, and in the absence of overriding factors, it's good engineering to keep the semantic complexity of a function low - it's easier to remember what bind does to a function if it treats all input functions in exactly the same way, as opposed to treating some input functions specially.
换句话说,bind 在“普通”函数上的工作方式与在 bind 返回的函数上的工作方式完全相同,并且在没有覆盖因素的情况下,保持函数的语义复杂性较低是一个很好的工程——更容易记住什么 bind如果一个函数以完全相同的方式处理所有输入函数,而不是专门处理某些输入函数,则对它进行处理。
I think your confusion is that you view bind as modifying an existing function, and you therefore, if you modify it again you expect the original function to be modified again. However, bind does not modify anything, it creates a new function with specific behaviour. The new function is a function in it's own right, it's not a magic patched version of the original function.
我认为您的困惑在于您将 bind 视为修改现有函数,因此,如果您再次修改它,您希望再次修改原始函数。然而,bind 不会修改任何东西,它会创建一个具有特定行为的新函数。新函数本身就是一个函数,它不是原始函数的魔法补丁版本。
As such, there is no mystery on why it was standardised or invented the way it was: bind returns a function that provides a new this and prepends arguments, and works the same on all functions. The simplest possible semantic.
因此,为什么它被标准化或发明它的方式并不神秘:bind 返回一个函数,该函数提供一个新的 this 并添加参数,并且在所有函数上都相同。最简单的语义。
Only this way is it actually safe to use - if bind would make a difference between already bound functions and "normal" ones, one would have to test before binding. A good example would be jQuery.each, which passes a new this. If bind would specialcase bound functions, there would be no safe way to pass a bound function into jQuery.each, as this will be overwritten on each call. To fix that, jQuery.each would have to specialcase bound functions somehow.
只有这样才能真正安全地使用——如果 bind 会在已经绑定的函数和“正常”函数之间产生差异,则必须在绑定之前进行测试。一个很好的例子是 jQuery.each,它传递一个新的 this。如果绑定将特殊情况绑定函数,将没有安全的方法将绑定函数传递到 jQuery.each,因为这将在每次调用时被覆盖。为了解决这个问题,jQuery.each 必须以某种方式对绑定函数进行特殊处理。