我知道当Function.prototype.bind
返回的函数被称为构造函数时,会忽略预绑定的this
。这是ECMA-262中指定的行为,以及MDN polyfill实现的行为。我的问题是:在这种情况下,polyfill如何工作?我知道这段代码对此有反应:
fNOP = function () {}
和
return fToBind.apply(this instanceof fNOP && oThis
? this
: oThis,
和
fNOP.prototype = this.prototype;
fBound.prototype = new fNOP();
但是为什么他们需要创建这个虚函数(fNOP
),实例化它并分配给fBound
的原型等等。为什么他们只能这样写:
fBound = function foo() {
return fToBind.apply(this instanceof foo
? this
: oThis,
aArgs.concat(Array.prototype.slice.call(arguments)));
};
答案 0 :(得分:1)
但是为什么他们需要创建这个虚拟函数(fNOP),实例化它并分配给fBound的原型等等。
如果用new调用绑定函数,那么this
将是FNOP的一个实例,这是因为返回函数的原型是FNOP的一个实例。
this instanceof fNOP
调用返回的值,则 new
将为true。但这只是因为返回的值具有FNOP的实例,因为它是原型。
如果您不想创建虚拟函数并执行:
fBound = function () {
return fToBind.apply(this instanceof fBound && oThis
然后你将如何设置fBound的原型?你可以尝试:
fBound.prototype = new fToBind();
但是传递的函数在没有参数的情况下调用时可能抛出异常,你可以这样做:
fBound.prototype = Object.create(fToBind.prototype);
但是你需要polyfil for Object.create,而且polyfill基本上做同样的事情;创建一个虚拟函数,设置它的原型并创建一个虚函数的实例,让一个对象具有它的原型集。
答案 1 :(得分:1)
填充bind
很难,甚至不可能做到相关。如果你看一下spec,你会注意到绑定函数是Function对象
.prototype
属性.length
属性显然,第一个质量是最重要的,所以我们所做的就是返回一个表现出这种行为的函数。您已经注意到并非一切都可以正常完成,因为.length
函数是不可写的,并且prototype
(隐式创建)是不可删除的。
那么如何实现[[Construct]]?我们需要确定是否使用new
表达式调用该函数。在.call()
/ .apply()
和Object.create()
的帮助下,new
call could be faked无法可靠地完成此操作。所以通常做的是测试Object.getPrototypeOf(this) === constructor.prototype
,或更简单的this instanceof constructor
。如果需要,我们会伪造带有扩展参数的待绑定函数的[[Construct]]调用。
那么如何实现[[HasInstance]]?操纵它的唯一方法是.prototype
的值,它用于原型链查找。要使fBound.[[HasInstance]]
的工作方式与fToBind.[[HasInstance]]
相同,我们需要设置fBound.prototype = fToBind.prototype
。
但是,如果我们这样做,当在绑定函数的实例上调用绑定函数时,[[Construct]]检查将失败。 HMM。
因此,我们需要平衡可能解决方案的权衡。 MDN polyfill可以按照您的建议方式进行更改,可以更改为通过Object.create(fToBind.prototype)
而不是this
等。
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 |