super-implementations

JavaScript performance comparison

Test case created

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 : {};
       
        // 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.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)';
        };
    });
   
    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 unknown unknown
Test Ops/sec
original
john.name();
pending…
methodName
john.name2();
pending…
closure wrap
john.name3();
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. Here’s a list of current revisions for this page:

0 comments

Add a comment