MDN Function.prototype.bind bound function called as constructor

后端 未结 2 1180
别那么骄傲
别那么骄傲 2021-01-03 17:08

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 sp

2条回答
  •  半阙折子戏
    2021-01-03 17:58

    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

    • 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

    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.

    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.

    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.

    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.

    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   |
    

提交回复
热议问题