How is `new` operator able to override hard-binding, in the Function.prototype.bind(..)
First, it is important to understand the difference between an object's prototype (represented the spec as [[Prototype]]
and accessible via the function Object.getPrototypeOf
or the deprecated __proto__
property) and the property on a function whose name is prototype
. Every function has a property named prototype
which is used when the function is called with new
.
When you call a function with new
, that function is supplied with a this
value set to a newly-constructed object whose prototype (i.e., [[Prototype]]
) is set to the prototype
property of the function being called. That is, when you call new Foo()
, then when the code inside Foo
is run, the this
value will be an object of the form
{ [[Prototype]]: Foo.prototype }
Let's briefly meet the cast of variables:
fToBind
is the function being bound: forfoo.bind(...)
,foo
isfToBind
.fBound
is the bound version offToBind
; it is the returned value of thebind
operation.fBound
acts like a gatekeeper for the originalfToBind
function, and decides whatthis
valuefToBind
gets when it is invoked.oThis
is the first argument supplied tobind
, i.e., the object being bound to the function'sthis
.fNOP
is a function whoseprototype
property is set tofToBind.prototype
fBound.prototype = new fNOP()
causes these to be true:Object.getPrototypeOf(fBound.prototype) === fNOP.prototype Object.getPrototypeOf(fBound.prototype) === fToBind.prototype
When fBound
is called with new
, then the this
that is supplied to fBound
is of the form
{ [[Prototype]]: fBound.prototype }
and fBound.prototype
is an object of the form
{ [[Prototype]]: fNOP.prototype }
making the full form of this
equivalent to
{ [[Prototype]]: { [[Prototype]]: fNOP.prototype } }
So, fNOP.prototype
is in the prototype chain of the newly-created this
object when fBound
is called with new
. That's exactly what the object instanceof constructor
operation tests for:
The
instanceof
operator tests the presence ofconstructor.prototype
inobject
's prototype chain.
The order of operations between &&
and ternary here is:
(this instanceof fNOP && oThis) ? this : oThis
If this
has fNOP.prototype
in its prototype chain and the original bind
call was given a truthy first argument to bind to the function, then use the natrually-created this
supplied to fBound
when it is called with new
and supply that to fToBind
instead of the bound this
.