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.
Still can not understand why should we check '&& oThis', is it means if we pass a null to bind like s = f.bind(null), then no matter use s as constructor -- new s,or normal function invoke -- s(), we always pass null to f.apply as f.apply(null,.....)? And then the null will be force change to global inside the function call f.apply. Why do me do this? Can you please help me out? thanks a lot in advance!