function calls: direct vs apply vs call vs bind

JavaScript performance comparison

Revision 75 of this test case created by me

Preparation code


      
      <script>
Benchmark.prototype.setup = function() {
  function f() {
      return this;
  }
  var that = {
      f: f
  };
  var bound = f.bind(that);
  var that2 = Object.create(that);
  var that3 = {};
  var that4 = Object.create(that3);
  
  function bind(fn, thisArg) {
    var boundArgs;
    if (arguments.length > 2) {
      boundArgs = new Array(arguments.length - 2);
      for (var i = 0, a = 2; a < arguments.length; ++i, ++a)
        boundArgs[i] = arguments[a];
    } else
      boundArgs = [];
  
    if (thisArg) {
      return function() {
        var callArgs;
        if (arguments.length > 0) {
          callArgs = boundArgs.slice(0);
          for (var i = 0; i < arguments.length; ++i)
            callArgs[callArgs.length] = arguments[i];
        } else
          callArgs = boundArgs;
  
        var nArgs = callArgs.length;
  
        switch (nArgs) {
          case 0:
            return fn.call(thisArg);
            break;
          case 1:
            return fn.call(thisArg, callArgs[0]);
            break;
          case 2:
            return fn.call(thisArg, callArgs[0], callArgs[1]);
            break;
          case 3:
            return fn.call(thisArg, callArgs[0], callArgs[1], callArgs[2]);
            break;
          case 4:
            return fn.call(thisArg, callArgs[0], callArgs[1], callArgs[2],
                           callArgs[3]);
            break;
          case 5:
            return fn.call(thisArg, callArgs[0], callArgs[1], callArgs[2],
                           callArgs[3], callArgs[4]);
            break;
          case 6:
            return fn.call(thisArg, callArgs[0], callArgs[1], callArgs[2],
                           callArgs[3], callArgs[4], callArgs[5]);
            break;
          case 7:
            return fn.call(thisArg, callArgs[0], callArgs[1], callArgs[2],
                           callArgs[3], callArgs[4], callArgs[5], callArgs[6]);
            break;
          default:
            return fn.apply(thisArg, callArgs);
        }
      };
    } else {
      return function() {
        var callArgs;
        if (arguments.length > 0) {
          callArgs = boundArgs.slice(0);
          for (var i = 0; i < arguments.length; ++i)
            callArgs[callArgs.length] = arguments[i];
        } else
          callArgs = boundArgs;
  
        var nArgs = callArgs.length;
  
        switch (nArgs) {
          case 0:
            return fn();
            break;
          case 1:
            return fn(callArgs[0]);
            break;
          case 2:
            return fn(callArgs[0], callArgs[1]);
            break;
          case 3:
            return fn(callArgs[0], callArgs[1], callArgs[2]);
            break;
          case 4:
            return fn(callArgs[0], callArgs[1], callArgs[2], callArgs[3]);
            break;
          case 5:
            return fn(callArgs[0], callArgs[1], callArgs[2], callArgs[3],
                      callArgs[4]);
            break;
          case 6:
            return fn(callArgs[0], callArgs[1], callArgs[2], callArgs[3],
                      callArgs[4], callArgs[5]);
            break;
          case 7:
            return fn(callArgs[0], callArgs[1], callArgs[2], callArgs[3],
                      callArgs[4], callArgs[5], callArgs[6]);
            break;
          default:
            return fn.apply(null, callArgs);
        }
      };
    }
  }
  
  var bound2 = bind( f, that );
  var bound3 = bind( f );

};
</script>

Test runner

Warning! For accurate results, please disable Firebug before running the tests. (Why?)

Java applet disabled.

Testing in CCBot 2.0.0 / Other 0.0.0
Test Ops/sec
direct
that.f();
pending…
apply
f.apply(that);
pending…
call
f.call(that);
pending…
bind
bound();
pending…
prototype
that2.f();
pending…
direct (dynamic property)
that3.f = f; that3.f();
pending…
prototype (dynamic property)
that3.f = f; that4.f();
pending…
fast bind
bound2();
pending…
bind, no scope
bound3();
pending…

Compare results of other browsers

Revisions

You can edit these tests or add even more tests to this page by appending /edit to the URL.

0 Comments