I see in the Mozilla polyfill of fn.bind()
like this:
if (!Function.prototype.bind) {
Function.prototype.bind = function(oThis) {
if (typeof this !== 'function') {
// closest thing possible to the ECMAScript 5
// internal IsCallable function
throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable');
}
// other code omitted here...
};
}
I don't understand why we have to check the type of this
... because if we say fn.bind()
and fn
is a function, then it will work, and if fn
is not a function, then fn.bind
will never reach Function.prototype.bind
by prototypal inheritance. So why do we have to check the type of this
?
if
fn
is not a function, thenfn.bind
will never reachFunction.prototype.bind
by prototypal inheritance.
True, however this is not the only way this
could be set. For example, if we were to use the .call
or .apply
methods on the bind
function itself, or do something really crazy like assign it to other objects, it would behave differently from the native function.
Considering the following code using the native ES5 method:
var notAFunction = {};
var someObject = {};
Function.prototype.bind.call(notAFunction, someObject);
This will throw a TypeError
, like the following:
TypeError: Function.prototype.bind called on incompatible Object
This extra check is basically emulating this sanity check from the native function as closely as it can.
So why do we have to check the type of
this
?
You don't technically have to, as this case would be an edge-case for most sane code, but in order to make the polyfill behave more-closely to the ES5 spec, it is nice. Since ES5 browsers will never even run this code, there is also no performance hit for modern browser.
This behavior is defined in the ECMA-262 5.1 Edition specification and onward:
- Let Target be the this value.
- If IsCallable(Target) is false, throw a TypeError exception.
Not all callable objects inherit from (or are equal to) Function.prototype
. For example:
typeof document.createElement('object') === "function"; // true
document.createElement('object') instanceof Function; // false
And even objects which inherit from Function.prototype
could have bind
shadowed:
var f = function() {};
f.bind = 123;
f.bind === Function.prototype.bind; // false
However, you may want to be able to call Function.prototype.bind
on those callable objects. That's why we have things like Function.prototype.call
, Function.prototype.apply
or Reflect.apply
. You can use those to call bind
on any object, whether it's callable or not.
The inverse is also possible. You can have an object which inherits from Function.prototype
and is not callable. For example:
Object.create(Function.prototype) instanceof Function; // true
typeof Object.create(Function.prototype) === "function"; // false
Therefore, you can't make any assumption. If you want the polyfill to conform to ES5, you must check whether the object is callable. In ES5, checking whether typeof
returns "function"
does exactly that (but in ES3 it might not work for host objects).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With