问题描述
我知道当 Function.prototype.bind
返回的函数被调用为构造函数时,预绑定 this
被忽略。这是ECMA-262中指定的行为,以及实现。我的问题是:在这种情况下,polyfill如何工作?我知道这段代码对此有反应:
I know that when a function returned by Function.prototype.bind
is called as a constructor, the pre-bound this
is ignored. This is the behaviour specified in ECMA-262, and the behaviour that MDN polyfill implements. My question is: how that polyfill works in that case? I know that this code is responsoble for that:
fNOP = function () {}
和
return fToBind.apply(this instanceof fNOP && oThis
? this
: oThis,
和
fNOP.prototype = this.prototype;
fBound.prototype = new fNOP();
但为什么他们需要创建这个虚拟函数( fNOP
),实例化它并分配给 fBound
的原型等等。为什么他们只能这样写:
But why do they need to create this dummy function (fNOP
), instantiate it and assign to the fBound
's prototype and so on. Why can's they just write this:
fBound = function foo() {
return fToBind.apply(this instanceof foo
? this
: oThis,
aArgs.concat(Array.prototype.slice.call(arguments)));
};
?
推荐答案
Polyfilling bind
很难,如果不是e不可能做到相关的。如果您查看,您会注意到绑定函数是Function对象
Polyfilling bind
is hard, if not even impossible to do correclty. If you take a look at the spec, you notice that bound functions are Function objects
- 内部属性
- 带有内部属性
- ,带有内部属性
- 没有
.prototype
property - ,具有特定的
.length
属性
- with a custom [[Call]] internal property
- with a custom [[Construct]] internal property
- with a custom [[HasInstance]] internal property
- without a
.prototype
property - with a specific
.length
property
显然,第一个质量是最重要的,所以我们所做的就是返回一个表现出这种行为的函数。您已经注意到并非一切都可以正常完成,因为 .length
的函数是不可写的,而 prototype
(隐式创建)是不可删除的。
Clearly, that first quality is the most important, so what we do is to return a function that exhibits this behaviour. You already notice that not everything can be done properly, as .length
of functions is non-writable, and prototype
(implicitly created) is non-deleteable.
那么如何实现[[Construct]]?我们需要确定是否使用 new
表达式调用该函数。这不能可靠地完成,因为帮助 .call()
/ .apply()
和 Object.create()
。所以通常做的是测试 Object.getPrototypeOf(this)=== constructor.prototype
,或者更简单的只是这个instanceof构造函数
。如果需要,我们会伪造带有扩展参数的待绑定函数的[[Construct]]调用。
So how to implement [[Construct]]? We would need to determine whether the function was called with a new
expression. This cannot be done reliably, as a new
call could be faked with the help of .call()
/.apply()
and Object.create()
. So what is usually done is testing Object.getPrototypeOf(this) === constructor.prototype
, or more simple just this instanceof constructor
. If required, we then would fake the [[Construct]] call of the to-be-bound function with the extended arguments.
那么如何实现[[HasInstance] ]?操纵它的唯一方法是 .prototype
的值,它用于原型链查找。要使 fBound。[[HasInstance]]
的工作方式与 fToBind相同。[[HasInstance]]
,我们需要设置 fBound.prototype = fToBind.prototype
。
So how to implement [[HasInstance]]? The only way to manipulate this is the value of the .prototype
, which is used for the prototype chain lookups. To make fBound.[[HasInstance]]
work the same way as fToBind.[[HasInstance]]
, we need to set fBound.prototype = fToBind.prototype
.
但是,如果我们这样做,那就是[[Construct]当绑定函数的实例调用绑定函数时,]检查将失败。嗯。
However, if we do that, the is[[Construct]]ing check will fail us when the bound function is called on instances of the binded function. Hmm.
因此,我们需要平衡可能解决方案的权衡。可以按照建议的方式更改MDN polyfill,可以更改为传递 Object.create(fToBind.prototype)
而不是此
等。
So, we will need to balance the trade-offs of the possible solutions. The MDN polyfill could be changed in the way you suggest, could be changed to pass Object.create(fToBind.prototype)
instead of this
, etc.
Property | current MDN | your | … with same
| polyfill | solution | prototypes
------------------------------+-------------------------------------------
fBound(…) uses boundThis | yes yes yes
|
new fBound(…) ignores it | yes yes yes
|
fBound.call(new fToBind) | yes yes no
uses boundThis |
|
new fToBind instanceof fBound | no no yes
|
new fBound instanceof fBound | yes yes yes
|
new fBound instanceof fToBind | yes no yes
|
Object.getPrototypeOf(new | no no yes
fBound)==fToBind.prototype |
这篇关于MDN Function.prototype.bind绑定函数称为构造函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!