I met an issue with the common polyfill for Function.prototype.bind
, found on the MDN, and I do not know where to fix it.
Here is the polyfill:
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');
}
var aArgs = Array.prototype.slice.call(arguments, 1),
fToBind = this,
fNOP = function() {},
fBound = function() {
return fToBind.apply(this instanceof fNOP && oThis
? this
: oThis,
aArgs.concat(Array.prototype.slice.call(arguments)));
};
fNOP.prototype = this.prototype;
fBound.prototype = new fNOP();
return fBound;
};
}
I was trying to unit test some React components usign a Mocha / PhantomJS wrapper for Gulp. This gulp task uses PhantomJS v1.9, that does not have Function.prototype.bind
support (source). And Function.prototype.bind
is used some times in React source code, so I used the polyfill.
When I ran my script, I received the following error:
TypeError: instanceof called on an object with an invalid prototype property.
After some investigations, I found that there is a specific call of bind
from React that made the polyfill crash (link):
var HTMLDOMPropertyConfig = {
isCustomAttribute: RegExp.prototype.test.bind(
/^(data|aria)-[a-z_][a-z\d_.\-]*$/
)
// [...]
};
RegExp.prototype.test
is a native function and has no prototype, so the line fNOP.prototype = this.prototype;
was setting fNOP
's prototype to undefined
, which made the test this instanceof fNOP
throw the error: the right operand of instanceof
must have an object prototype.
After having discussed with @rauschma on Twitter, he told me that this while fNOP
's related code is certainly here to deal with using a bound function as a constructor, which makes sense.
I think that just testing that the function to bind has actually a prototype before setting it as fNOP.prototype
would solve the issue. So the fixed version would be:
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');
}
var aArgs = Array.prototype.slice.call(arguments, 1),
fToBind = this,
fNOP = function() {},
fBound = function() {
return fToBind.apply(this instanceof fNOP && oThis
? this
: oThis,
aArgs.concat(Array.prototype.slice.call(arguments)));
};
// test this.prototype in case of native functions binding:
if (this.prototype)
fNOP.prototype = this.prototype;
fBound.prototype = new fNOP();
return fBound;
};
}
My problem is that:
- I do not know who is the original author
- I do not know if there is an existing tests suit for polyfills
- I do not know where to submit that fix if is the good way to solve my problem
A quick Github search shows that this polyfill is used in many places, and if it fails with binding native functions, it looks a bit dangerous to let that out.
Thanks 👍