MDN Function.prototype.bind绑定函数称为构造函数

时间:2014-05-16 05:36:06

标签: javascript polyfills

我知道当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)));
    };

2 个答案:

答案 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对象

显然,第一个质量是最重要的,所以我们所做的就是返回一个表现出这种行为的函数。您已经注意到并非一切都可以正常完成,因为.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   |