When comparing this benchmark with chrome 16 vs opera 11.6 we find that
Where an emulated version of bind in this case is
var emulatebind = function (f, context) { return function () { f.apply(context, arguments); }; };
Are there good reasons why there is such a difference or is this just a matter of v8 not optimizing enough?
Note: that emulatebind
only implements a subset but that isn't really relevant. If you have a fully featured and optimised emulated bind the performance difference in the benchmark still exists.
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.
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