Based on http://jsperf.com/bind-vs-emulate/6, which adds the es5-shim version for comparison, it looks like the culprit is the extra branch and instanceof
that the bound version has to perform to test if it’s being called as a constructor.
Each time the bound version is run, the code that gets executed is essentially:
if (this instanceof bound) {
// Never reached, but the `instanceof` check and branch presumably has a cost
} else {
return target.apply(
that,
args.concat(slice.call(arguments))
);
// args is [] in your case.
// So the cost is:
// * Converting (empty) Arguments object to (empty) array.
// * Concating two empty arrays.
}
In the V8 source code, this check appears (inside boundFunction
) as
if (%_IsConstructCall()) {
return %NewObjectFromBound(boundFunction);
}
(Plaintext link to v8natives.js for when Google Code Search dies.)
It is a bit puzzling that, for Chrome 16 at least, the es5-shim version is still faster than the native version. And that other browsers have rather varying results for es5-shim vs. native. Speculation: maybe %_IsConstructCall()
is even slower than this instanceof bound
, perhaps due to crossing native/JS code boundaries. And perhaps other browsers have a much faster way of checking for a [[Construct]]
call.