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
But why do they need to create this dummy function (fNOP), instantiate it and assign to the fBound's prototype and so on.
In case your bound function is called with new then this
will be an instance of FNOP, this because the prototype of the returned function is an instance of FNOP.
this instanceof fNOP
will be true if I invoke the returned value with new
. But only because the returned value has an instance of FNOP as it's prototype.
If you would not create a dummy function and do:
fBound = function () {
return fToBind.apply(this instanceof fBound && oThis
Then how would you set fBound's prototype? You could try:
fBound.prototype = new fToBind();
But the passed function may throw an exception when called without parameters, you could do:
fBound.prototype = Object.create(fToBind.prototype);
But then you need the polyfil for Object.create as well and that polyfill basically does the same thing; create a dummy function, set it's prototype and create an instance of the dummy function to have an object with it's prototype set.
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
propertyClearly, 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 |