super-implementations

JavaScript performance comparison

Revision 2 of this test case created by

Preparation code


      
      <script>
Benchmark.prototype.setup = function() {
  var F = function () {};
  
  function createClass (name, superclass, callback) {
      var theClass;
      
      // create the function constructor for the class
      theClass = function () {
          // verify class is always instantiated with 'new' keyword
          if (!(this instanceof theClass)) {
              throw new Error('[' + name + '] Please use "new" keyword to instantiate class');
          }
          this.init.apply(this, arguments);
      };
  
      // Setup display name and superclass
      theClass.displayName = theClass._name = name;
  
      // store class in window
      window[name] = theClass;
  
      // inherit from the superclass unless we're processing the base class
      if (superclass) {
          F.prototype = superclass.prototype;
          theClass.superclass = superclass;
          theClass.prototype = new F();
          theClass.prototype.constructor = theClass;
      }
      superclass = theClass.superclass ? theClass.superclass.prototype : {};
      Object.defineProperty(theClass.prototype, 'super', {
          configurable: false,
          enumerable: false,
          value: superclass,
          writable: false
      });
      
      // invoke callback to "implement" class and process it afterwards 
      callback(theClass);
      
      // process instance (prototype) methods of the class
      for (var method in theClass.prototype) {
          if (!theClass.prototype.hasOwnProperty(method)) {
              return;
          }
          processMethod(theClass, method);
          
          // if method uses .callSuper, use a closure to keep reference of the corresponding superclass' method
          if ((typeof superclass[method] === 'function') && /this\.callSuper3\(/.test(theClass.prototype[method])) {
              theClass.prototype[method] = overrideCallSuper(theClass.prototype[method], superclass[method]);
          }
      }
      
  }
  
  function processMethod (theClass, methodName) {
      var parent = theClass.prototype;
      var prop = Object.getOwnPropertyDescriptor(parent, methodName).value;
  
      // only process functions
      if (typeof prop !== 'function') {
          return;
      }
  
      prop._class = theClass;
      prop._name = methodName;
  
      if (!prop.displayName) {
          prop.displayName = theClass.displayName + '#' + methodName + '()';
      }
  }
  
  function overrideCallSuper (method, superMethod) {
      return function () {
          // locally store existing callSuper to avoid overwriting it if it already exists
          var callSuper = this.callSuper3;
          var results;
  
          // override the callSuper method with the actual's superclass method
          // and call the actual method
          this.callSuper3 = superMethod;
          results = method.apply(this, arguments);
          // restore callSuper and return results
          this.callSuper3 = callSuper;
          return results;
      };
  }
  
  
  createClass('Person', null, function () {
      
      Person.prototype.init = function (firstName, lastName) {
          this.firstName = firstName;
          this.lastName = lastName;
      };
      
      Person.prototype.name = function (msg) {
          return '1. ' + this.firstName + ' ' + this.lastName;
      };
  
      Person.prototype.name2 = function (msg) {
          return '2. ' + this.firstName + ' ' + this.lastName;
      };
      
      Person.prototype.name3 = function (msg) {
          return '3. ' + this.firstName + ' ' + this.lastName;
      };
  
      Person.prototype.name4 = function (msg) {
          return '4. ' + this.firstName + ' ' + this.lastName;
      };
  
      Person.prototype.callSuper = function () {
          // figure out what function called us
          var caller = Person.prototype.callSuper.caller;
          var parent = caller._class.superclass.prototype;
          var method_name = caller._name;
          return parent[method_name].apply(this, arguments);
      };
  
       Person.prototype.callSuper2 = function (methodName) {
           var args = Array.prototype.slice.call(arguments); 
           return this.constructor.superclass.prototype[methodName].apply(this, args.slice(1));
       };
  });
  
  createClass('Employee', Person, function () {
      
      Employee.prototype.init = function (firstName, lastName, title) {
          this.firstName = firstName;
          this.lastName = lastName;
          this.title = title;
      };
      
      Employee.prototype.name = function (msg) {
          return this.callSuper() + ' (Employed)';
      };
  
      Employee.prototype.name2 = function (msg) {
          return this.callSuper2('name2') + ' (Employed)';
      };
      
      Employee.prototype.name3 = function (msg) {
          return this.callSuper3() + ' (Employed)';
      };
  
      Employee.prototype.name4 = function (msg) {
          return this.super.name4.call(this, msg);
      }
  });
  
  var john = new Employee('John', 'Smith', 'Assistant');

};
</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
original
john.name();
pending…
methodName
john.name2();
pending…
closure wrap
john.name3();
pending…
super property
john.name4();
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