Moo-Resig-Ender-My

JavaScript performance comparison

Revision 6 of this test case created by Jakub

Info

Comparing Mootools, John Resig, Ender & My.js class systems on class instantiation. Check the scripts MooTest.js, JRTest.js, EnderTest.js, MyTest.js.

Preparation code

<script src="http://myjs.fr/my-class/example/MooClass.js"></script>
<script src="http://myjs.fr/my-class/example/JRClass.js"></script>
<script src="http://myjs.fr/my-class/example/EnderClass.js"></script>
<script src="http://myjs.fr/my-class/my.class.min.js"></script>
<script src="http://myjs.fr/my-class/example/MooTest.js"></script>
<script src="http://myjs.fr/my-class/example/JRTest.js"></script>
<script src="http://myjs.fr/my-class/example/EnderTest.js"></script>
<script src="http://myjs.fr/my-class/example/MyTest.js"></script>
<script>
 
  ;(function(undefined) {
    var
      CLASSY_VERSION = '1.4',
      root = this,
      old_class = root.Class,
      disable_constructor = false;
 
    /* we check if $super is in use by a class if we can.  But first we have to
       check if the JavaScript interpreter supports that.  This also matches
       to false positives later, but that does not do any harm besides slightly
       slowing calls down. */

    var probe_super = (function(){$super();}).toString().indexOf('$super') > 0;
    function usesSuper(obj) {
      return !probe_super || /\B\$super\b/.test(obj.toString());
    }
 
    /* helper function to set the attribute of something to a value or
       removes it if the value is undefined. */

    function setOrUnset(obj, key, value) {
      if (value === undefined)
        delete obj[key];
      else
        obj[key] = value;
    }
 
    /* gets the own property of an object */
    function getOwnProperty(obj, name) {
      return Object.prototype.hasOwnProperty.call(obj, name)
        ? obj[name] : undefined;
    }
 
    /* instanciate a class without calling the constructor */
    function cheapNew(cls) {
      disable_constructor = true;
      var rv = new cls;
      disable_constructor = false;
      return rv;
    }
 
    /* the base class we export */
    var Class = function() {};
 
    /* restore the global Class name and pass it to a function.  This allows
       different versions of the classy library to be used side by side and
       in combination with other libraries. */

    Class.$noConflict = function() {
      try {
        setOrUnset(root, 'Class', old_class);
      }
      catch (e) {
        // fix for IE that does not support delete on window
        root.Class = old_class;
      }
      return Class;
    };
 
    /* what version of classy are we using? */
    Class.$classyVersion = CLASSY_VERSION;
 
    /* extend functionality */
    Class.$extend = function(properties) {
      var super_prototype = this.prototype;
 
      /* disable constructors and instanciate prototype.  Because the
         prototype can't raise an exception when created, we are safe
         without a try/finally here. */

      var prototype = cheapNew(this);
 
      /* copy all properties of the includes over if there are any */
      if (properties.__include__)
        for (var i = 0, n = properties.__include__.length; i != n; ++i) {
          var mixin = properties.__include__[i];
          for (var name in mixin) {
            var value = getOwnProperty(mixin, name);
            if (value !== undefined)
              prototype[name] = mixin[name];
          }
        }
   
      /* copy class vars from the superclass */
      properties.__classvars__ = properties.__classvars__ || {};
      if (prototype.__classvars__)
        for (var key in prototype.__classvars__)
          if (!properties.__classvars__[key]) {
            var value = getOwnProperty(prototype.__classvars__, key);
            properties.__classvars__[key] = value;
          }
 
      /* copy all properties over to the new prototype */
      for (var name in properties) {
        var value = getOwnProperty(properties, name);
        if (name === '__include__' ||
            value === undefined)
          continue;
 
        prototype[name] = typeof value === 'function' && usesSuper(value) ?
          (function(meth, name) {
            return function() {
              var old_super = getOwnProperty(this, '$super');
              this.$super = super_prototype[name];
              try {
                return meth.apply(this, arguments);
              }
              finally {
                setOrUnset(this, '$super', old_super);
              }
            };
          })(value, name) : value
      }
 
      /* dummy constructor */
      var rv = function() {
        if (disable_constructor)
          return;
        var proper_this = root === this ? cheapNew(arguments.callee) : this;
        if (proper_this.__init__)
          proper_this.__init__.apply(proper_this, arguments);
        proper_this.$class = rv;
        return proper_this;
      }
 
      /* copy all class vars over of any */
      for (var key in properties.__classvars__) {
        var value = getOwnProperty(properties.__classvars__, key);
        if (value !== undefined)
          rv[key] = value;
      }
 
      /* copy prototype and constructor over, reattach $extend and
         return the class */

      rv.prototype = prototype;
      rv.constructor = rv;
      rv.$extend = Class.$extend;
      rv.$withData = Class.$withData;
      return rv;
    };
 
    /* instanciate with data functionality */
    Class.$withData = function(data) {
      var rv = cheapNew(this);
      for (var key in data) {
        var value = getOwnProperty(data, key);
        if (value !== undefined)
          rv[key] = value;
      }
      return rv;
    };
 
    /* export the class */
    root.Class = Class;
  })();
 
  !function(a,b){function j(a,b){function c(){}c[e]=this[e];var d=this,g=new c,h=f(a),j=h?a:this,k=h?{}:a,l=function(){this.initialize?this.initialize.apply(this,arguments):(b||h&&d.apply(this,arguments),j.apply(this,arguments))};l.methods=function(a){i(g,a,d),l[e]=g;return this},l.methods.call(l,k).prototype.constructor=l,l.extend=arguments.callee,l[e].implement=l.statics=function(a,b){a=typeof a=="string"?function(){var c={};c[a]=b;return c}():a,i(this,a,d);return this};return l}function i(a,b,d){for(var g in b)b.hasOwnProperty(g)&&(a[g]=f(b[g])&&f(d[e][g])&&c.test(b[g])?h(g,b[g],d):b[g])}function h(a,b,c){return function(){var d=this.supr;this.supr=c[e][a];var f=b.apply(this,arguments);this.supr=d;return f}}function g(a){return j.call(f(a)?a:d,a,1)}var c=/xyz/.test(function(){xyz})?/\bsupr\b/:/.*/,d=function(){},e="prototype",f=function(a){return typeof a===b};if(typeof module!="undefined"&&module.exports)module.exports=g;else{var k=a.klass;g.noConflict=function(){a.klass=k;return this},a.klass=g}}(this,"function")
 
  var Animal = Class.$extend({
    __init__ : function(name) {
      this.name = name;
    }
  });
 
  var Person = klass(function (name) {
    this.name = name;
  })
</script>

Preparation code output

Test runner

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

Java applet disabled.

Testing in unknown unknown
Test Ops/sec
MooPerson instantiation
new MooPerson('John Doe');
pending…
JRPerson instantiation
new JRPerson('John Doe');
pending…
EnderPerson instantiation
new EnderPerson('John Doe');
pending…
MyPerson instantiation
new MyPerson('John Doe');
pending…
Classy
new Animal('Jakub')
pending…
Klass
new Person("Olek")
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