super-implementations
JavaScript performance comparison
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.
| Test | Ops/sec | |
|---|---|---|
original |
|
pending… |
methodName |
|
pending… |
closure wrap |
|
pending… |
super property |
|
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:
- Revision 1: published
- Revision 2: published
- Revision 3: published
0 comments