Prototype vs Module pattern performance (v155)

Revision 155 of this benchmark created on


Description

I have refactored these tests entirely.

Someone wrote the formulation:

for (var i=2000; i=0; i--) {

}

Possibly they did not notice that any statement contained by those curly braces will never execute. Paste the following into your JS console:

for (var i=2000; i=0; i--) { throw "An error"; }

You will never see the error "An error" thrown. "i=0" is falsy false. Presumably their intention was that this line should not execute; in which case, I can't see the point of it. Each test instantiated one object outside the "for" loop, regardless, but I think it's strange to include statements which do nothing.

Assuming that the object literal "objectLiteral" had been defined in the preparation or set-up code, someone had also written the statement:

a.push(new objectLiteral());

Because this statement appeared inside the curly braces of the never-executing "for" loop, a lurking error had never been thrown: "objectLiteral" is not a constructor.

I have refactored the object literal test to include the creation of the object literal; anything else does not seem to be a valid test of object creation. Every other test instantiates an object with "new"; pointing a variable at an object which has already been created outside of the test isn't the same thing, which will account for that test outperforming all of the other tests.

o = new ConstructedObject();

And

o = { };

Are as equivalent as can be, assuming only that the constructor "ConstructedObject" is defined outside the test, in the preparation code or set-up. If "objectLiteral" had been defined outside the test, similarly, then this following statement would not be equivalent to either of those above:

o = objectLiteral;

It simply assigns the existing object "objectLiteral" to variable "o".

Some tests use function declarations while others use function expressions. Again, these are not entirely equivalent but for the most part I haven't massaged those inequivalences away.

I have refactored all the methods to do something, and removed all references to the console within those methods, because that seems to be something too much. Since the never-executing "for" loop was duplicated within the test, the statements the duplicated loop contained were not executing, either: I have removed everything that they contained, and deleted the array "a" that was not being populated.

Preparation HTML

<script>
  function TraditionalPrototypeClass() {}
  TraditionalPrototypeClass.prototype.foo = function() {
    return 'foo';
  };
  TraditionalPrototypeClass.prototype.bar = function() {
    return 'bar';
  };

  function TraditionalClass() {

    this.foo = function() {
      return 'foo';
    };

    this.bar = function() {
      return 'bar';
    };

  }

  function ConstructOther() {
    //often seen in frameworks
    // constructor, but creates other object
    // this one is to be compared with traditional and literal versions
    return {
      foo: function() {
        return 'foo';
      },
      bar: function() {
        return 'bar';
      }
    };
  }

  var ModulePatternTraditionalPrototypeClass = (function() {
  var ModulePatternTraditionalPrototypeClass = (function() {

    function ModulePatternTraditionalPrototypeClass() {}
    ModulePatternTraditionalPrototypeClass.prototype.foo = function() {
      return 'foo';
    };
    ModulePatternTraditionalPrototypeClass.prototype.bar = function() {
      return 'bar';
    }

    return ModulePatternTraditionalPrototypeClass;

  }());
return new ModulePatternTraditionalPrototypeClass();}

var ModulePatternTraditionalPrototypeWithPropertyClass = (function() {
    function ModulePatternTraditionalPrototypeWithPropertyClass(name, age) {
this.name = name;
this.name = age;
}
    ModulePatternTraditionalPrototypeWithPropertyClass.prototype.foo = function() {
      return 'foo';
    };
    ModulePatternTraditionalPrototypeWithPropertyClass.prototype.bar = function() {
      return 'bar';
    }

    return ModulePatternTraditionalPrototypeWithPropertyClass;

  }());

  var ModulePatternTraditionalClass = (function() {

    function foo() {
      return 'foo';
    }

    function bar() {
      return 'bar';
    }

    return function() {
      this.foo = foo;
      this.bar = bar;
    };

  }());

  function FakeClass() {

    function __constructor() {
      this.init();
    }

    __constructor.prototype.init = function() {};

    __constructor.prototype.foo = function() {
      return 'foo';
    };

    __constructor.prototype.bar = function() {
      return 'bar';
    };

    return new __constructor();

  }

  function FakeClassWithoutInit() {

    function __constructor() {}

    __constructor.prototype.foo = function() {
      return 'foo';
    };

    __constructor.prototype.bar = function() {
      return 'bar';
    };

    return new __constructor();

  }
</script>

Setup

var o;

Test runner

Ready to run.

Testing in
TestOps/sec
Traditional Prototypal Class
o = new TraditionalPrototypeClass();
ready
Traditional Class
o = new TraditionalClass();
ready
Object Literal
o = {

  foo: function() {
    return 'a';
  },
  bar: function() {
    return 'b';
  }

};
ready
Fake Class
o = new FakeClass();
ready
Fake Class without init
o = new FakeClassWithoutInit();
ready
Module Pattern Traditional Prototype Class
o = ModulePatternTraditionalPrototypeClass();
ready
Module Pattern Traditional Class
o = new ModulePatternTraditionalClass();
ready
ConstructOther
o = new ConstructOther();
ready
ModulePatternTraditionalPrototypeWithPropertyClass
o = new ModulePatternTraditionalPrototypeWithPropertyClass('kim', 'age');
ready

Revisions

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