Type.js versus Class.js

JavaScript performance comparison

Revision 2 of this test case created by Ben Clinkinbeard

Info

Testing performance of stripped down inheritance versus John Resig's Class.js. Class.js appears to slow down the further down the inheritance tree you go, while Type.js does not.

Preparation code

<script src="//cdnjs.cloudflare.com/ajax/libs/lodash.js/1.0.1/lodash.min.js">
</script>
<script>
Benchmark.prototype.setup = function() {
    var data = [{
      "name": "2% Milk",
      "unit": "Cup",
      "p": 8,
      "f": 5,
      "c": 12,
      "_id": "512ae0c67fdfe7e449000001",
      "__v": 0
    }, {
      "name": "2% Shredded Cheddar Cheese",
      "unit": "Cup",
      "p": 28,
      "f": 24,
      "c": 0,
      "_id": "512ae0c67fdfe7e449000002",
      "__v": 0
    }, {
      "name": "Almonds - Sliced",
      "unit": "Tbsp",
      "p": 2,
      "f": 4,
      "c": 1,
      "_id": "512ae0c67fdfe7e449000003",
      "__v": 0
    }, {
      "name": "Banana",
      "unit": "Ounce",
      "p": 0,
      "f": 0,
      "c": 6,
      "_id": "512ae0c67fdfe7e449000004",
      "__v": 0
    }, {
      "name": "Banana Chocolate Chip Muffin",
      "unit": "Muffin",
      "p": 2.25,
      "f": 2.75,
      "c": 21.75,
      "_id": "512b8c4fcac258a65c000001",
      "__v": 0
    }, {
      "name": "Boar's Head Sweet Slice Ham",
      "unit": "Ounce",
      "p": 5,
      "f": 1.25,
      "c": 0.5,
      "_id": "512ae0c67fdfe7e449000005",
      "__v": 0
    }, {
      "name": "Broccoli",
      "unit": "100g",
      "p": 2,
      "f": 0,
      "c": 7,
      "_id": "512ae0c67fdfe7e449000006",
      "__v": 0
    }, {
      "name": "Chicken Breast",
      "unit": "Ounce",
      "p": 8.7,
      "f": 1,
      "c": 0,
      "_id": "512ae0c67fdfe7e449000007",
      "__v": 0
    }, {
      "name": "Chicken Thigh",
      "unit": "Ounce",
      "p": 4.5,
      "f": 4.7,
      "c": 0,
      "_id": "512ae0c67fdfe7e449000008",
      "__v": 0
    }, {
      "name": "Chipotle Bowl: Chicken, Cheese",
      "unit": "Serving",
      "p": 48,
      "f": 21,
      "c": 55,
      "_id": "512ae0c67fdfe7e449000009",
      "__v": 0
    }, {
      "name": "Chipotle Bowl: Chicken, Sour Cream, Cheese",
      "unit": "Serving",
      "p": 50,
      "f": 31,
      "c": 57,
      "_id": "512ae0c67fdfe7e44900000a",
      "__v": 0
    }, {
      "name": "Chipotle Salad: Chicken, Cheese",
      "unit": "Serving",
      "p": 46,
      "f": 17,
      "c": 25,
      "_id": "512ae0c67fdfe7e44900000b",
      "__v": 0
    }, {
      "name": "Chipotle Salad: Chicken, Sour Cream, Cheese",
      "unit": "Serving",
      "p": 48,
      "f": 27,
      "c": 27,
      "_id": "512ae0c67fdfe7e44900000c",
      "__v": 0
    }, {
      "name": "Chipotle Salad: Chicken, Sour Cream, Cheese, Dressing",
      "unit": "Serving",
      "p": 48,
      "f": 51.5,
      "c": 39,
      "_id": "512ae0c67fdfe7e44900000d",
      "__v": 0
    }, {
      "name": "Chipotle: Black Beans",
      "unit": "Serving",
      "p": 7,
      "f": 1,
      "c": 23,
      "_id": "512ae0c67fdfe7e44900000e",
      "__v": 0
    }, {
      "name": "Chipotle: Cheese",
      "unit": "Serving",
      "p": 8,
      "f": 8.5,
      "c": 0,
      "_id": "512ae0c67fdfe7e44900000f",
      "__v": 0
    }, {
      "name": "Chipotle: Chicken",
      "unit": "Serving",
      "p": 32,
      "f": 6.5,
      "c": 1,
      "_id": "512ae0c67fdfe7e449000010",
      "__v": 0
    }, {
      "name": "Chipotle: Guacamole",
      "unit": "Serving",
      "p": 2,
      "f": 13,
      "c": 8,
      "_id": "512ae0c67fdfe7e449000011",
      "__v": 0
    }, {
      "name": "Chipotle: Lettuce",
      "unit": "Serving",
      "p": 1,
      "f": 0,
      "c": 2,
      "_id": "512ae0c67fdfe7e449000012",
      "__v": 0
    }, {
      "name": "Chipotle: Pinto Beans",
      "unit": "Serving",
      "p": 7,
      "f": 1,
      "c": 22,
      "_id": "512ae0c67fdfe7e449000013",
      "__v": 0
    }, {
      "name": "Chipotle: Salad Dressing",
      "unit": "Serving",
      "p": 0,
      "f": 24.5,
      "c": 12,
      "_id": "512ae0c67fdfe7e449000014",
      "__v": 0
    }, {
      "name": "Chipotle: Sour Cream",
      "unit": "Serving",
      "p": 2,
      "f": 10,
      "c": 2,
      "_id": "512ae0c67fdfe7e449000015",
      "__v": 0
    }, {
      "name": "Chipotle: Steak",
      "unit": "Serving",
      "p": 30,
      "f": 6.5,
      "c": 2,
      "_id": "512ae0c67fdfe7e449000016",
      "__v": 0
    }, {
      "name": "Colby Cheese",
      "unit": "Ounce",
      "p": 7,
      "f": 9,
      "c": 1,
      "_id": "512ae0c67fdfe7e449000017",
      "__v": 0
    }, {
      "name": "Cool Whip - Fat Free",
      "unit": "Tbsp",
      "p": 0,
      "f": 0,
      "c": 1.5,
      "_id": "512ae0c67fdfe7e449000018",
      "__v": 0
    }, {
      "name": "Deli Turkey",
      "unit": "Ounce",
      "p": 4,
      "f": 1,
      "c": 2,
      "_id": "512ae0c67fdfe7e449000019",
      "__v": 0
    }, {
      "name": "Egg",
      "unit": "1 Large",
      "p": 6,
      "f": 6,
      "c": 0,
      "_id": "512ae0c67fdfe7e44900001a",
      "__v": 0
    }, {
      "name": "Egg White",
      "unit": "1 Large",
      "p": 4,
      "f": 0,
      "c": 0,
      "_id": "512ae0c67fdfe7e44900001b",
      "__v": 0
    }, {
      "name": "Feta Cheese",
      "unit": "Tbsp",
      "p": 1.3,
      "f": 2,
      "c": 0.375,
      "_id": "512ae0c67fdfe7e44900001c",
      "__v": 0
    }, {
      "name": "Harvest Land Turkey Burger",
      "unit": "Patty",
      "p": 20,
      "f": 9,
      "c": 0,
      "_id": "512ae0c67fdfe7e44900001d",
      "__v": 0
    }, {
      "name": "Hellmann's Light Mayo",
      "unit": "Tbsp",
      "p": 0,
      "f": 3.5,
      "c": 0.75,
      "_id": "512ae0c67fdfe7e44900001e",
      "__v": 0
    }, {
      "name": "Hershey's Syrup",
      "unit": "Tbsp",
      "p": 0,
      "f": 0,
      "c": 12,
      "_id": "512ae0c67fdfe7e44900001f",
      "__v": 0
    }, {
      "name": "Jack Link's Peppered Beef Jerky",
      "unit": "Ounce",
      "p": 15,
      "f": 1,
      "c": 4,
      "_id": "512ae0c67fdfe7e449000020",
      "__v": 0
    }, {
      "name": "Jack Link's Teriyaki Beef Jerky",
      "unit": "Ounce",
      "p": 14,
      "f": 1,
      "c": 5,
      "_id": "512ae0c67fdfe7e449000021",
      "__v": 0
    }, {
      "name": "Jello Sugar Free Pudding - Chocolate",
      "unit": "Serving",
      "p": 1,
      "f": 1.5,
      "c": 13,
      "_id": "512ae0c67fdfe7e449000022",
      "__v": 0
    }, {
      "name": "Jello Sugar Free Pudding - Dulce de Leche",
      "unit": "Serving",
      "p": 1,
      "f": 1,
      "c": 12,
      "_id": "512ae0c67fdfe7e449000023",
      "__v": 0
    }, {
      "name": "Kashi Oatmeal Dark Chocolate Cookie",
      "unit": "Cookie",
      "p": 2,
      "f": 5,
      "c": 20,
      "_id": "512ae0c67fdfe7e449000024",
      "__v": 0
    }, {
      "name": "Kashi Toasted Berry Crumble",
      "unit": "Cup",
      "p": 12,
      "f": 4.6,
      "c": 46.5,
      "_id": "512ae0c67fdfe7e449000025",
      "__v": 0
    }, {
      "name": "Kroger Honey Whole Wheat Bread",
      "unit": "Slice",
      "p": 4,
      "f": 1,
      "c": 16,
      "_id": "512ae0c67fdfe7e449000026",
      "__v": 0
    }, {
      "name": "Kroger Mini Cheese Ravioli",
      "unit": "Cup",
      "p": 11,
      "f": 8,
      "c": 35,
      "_id": "512ae0c67fdfe7e449000027",
      "__v": 0
    }, {
      "name": "Liberté Greek Yogurt - Blueberry",
      "unit": "Serving",
      "p": 11,
      "f": 0,
      "c": 20,
      "_id": "512ae0c67fdfe7e449000028",
      "__v": 0
    }, {
      "name": "Liberté Greek Yogurt - Peach/Passion Fruit",
      "unit": "Serving",
      "p": 11,
      "f": 0,
      "c": 20,
      "_id": "512ae0c67fdfe7e449000029",
      "__v": 0
    }, {
      "name": "Liberté Greek Yogurt - Strawberry",
      "unit": "Serving",
      "p": 11,
      "f": 0,
      "c": 20,
      "_id": "512ae0c67fdfe7e44900002a",
      "__v": 0
    }, {
      "name": "Light Ranch Dressing",
      "unit": "Tbsp",
      "p": 0.5,
      "f": 4,
      "c": 1,
      "_id": "512ae0c67fdfe7e44900002b",
      "__v": 0
    }, {
      "name": "Nature's Own Whole Wheat Bread",
      "unit": "Slice",
      "p": 4,
      "f": 1,
      "c": 10,
      "_id": "512ae0c67fdfe7e44900002c",
      "__v": 0
    }, {
      "name": "Newman's Own Light Balsamic",
      "unit": "Tbsp",
      "p": 0,
      "f": 2,
      "c": 2,
      "_id": "512ae0c67fdfe7e44900002d",
      "__v": 0
    }, {
      "name": "Oikos Greek Yogurt - Strawberry",
      "unit": "Serving",
      "p": 12,
      "f": 0,
      "c": 19,
      "_id": "512ae0c67fdfe7e44900002e",
      "__v": 0
    }, {
      "name": "Outback: Filet & Grilled Shrimp",
      "unit": "Serving",
      "p": 45,
      "f": 24,
      "c": 6,
      "_id": "512ae0c67fdfe7e44900002f",
      "__v": 0
    }, {
      "name": "Outback: Grilled Asparagus",
      "unit": "Serving",
      "p": 2,
      "f": 4,
      "c": 3,
      "_id": "512ae0c67fdfe7e449000030",
      "__v": 0
    }, {
      "name": "Outback: Grilled Shrimp",
      "unit": "Serving",
      "p": 28,
      "f": 20,
      "c": 7,
      "_id": "512ae0c67fdfe7e449000031",
      "__v": 0
    }, {
      "name": "Outback: Mixed Veggies",
      "unit": "Serving",
      "p": 3,
      "f": 3,
      "c": 11,
      "_id": "512ae0c67fdfe7e449000032",
      "__v": 0
    }, {
      "name": "PB2",
      "unit": "Tbsp",
      "p": 2.5,
      "f": 0.75,
      "c": 2.5,
      "_id": "512ae0c67fdfe7e449000033",
      "__v": 0
    }, {
      "name": "Pita",
      "unit": "Serving",
      "p": 6,
      "f": 0,
      "c": 22,
      "_id": "512ae0c67fdfe7e449000034",
      "__v": 0
    }, {
      "name": "Pomegranate Dressing",
      "unit": "Tbsp",
      "p": 0,
      "f": 2.25,
      "c": 3,
      "_id": "512ae0c67fdfe7e449000035",
      "__v": 0
    }, {
      "name": "Pork Chop",
      "unit": "Ounce",
      "p": 7,
      "f": 3,
      "c": 0,
      "_id": "512ae0c67fdfe7e449000036",
      "__v": 0
    }, {
      "name": "Pork Tenderloin",
      "unit": "Ounce",
      "p": 7,
      "f": 1,
      "c": 0,
      "_id": "512ae0c67fdfe7e449000037",
      "__v": 0
    }, {
      "name": "Porkolicious BBQ Sauce",
      "unit": "Tbsp",
      "p": 0,
      "f": 0,
      "c": 5.5,
      "_id": "512ae0c67fdfe7e449000038",
      "__v": 0
    }, {
      "name": "Raspberries",
      "unit": "Cup",
      "p": 1,
      "f": 1,
      "c": 15,
      "_id": "512ae0c67fdfe7e449000039",
      "__v": 0
    }, {
      "name": "Reduced Sugar Craisins",
      "unit": "Tbsp",
      "p": 0,
      "f": 0,
      "c": 7.5,
      "_id": "512ae0c67fdfe7e44900003a",
      "__v": 0
    }, {
      "name": "Salami",
      "unit": "Ounce",
      "p": 4,
      "f": 6,
      "c": 1,
      "_id": "512ae0c67fdfe7e44900003b",
      "__v": 0
    }, {
      "name": "Shredded Cheddar Cheese",
      "unit": "Cup",
      "p": 28,
      "f": 36,
      "c": 2,
      "_id": "512ae0c67fdfe7e44900003c",
      "__v": 0
    }, {
      "name": "Skyline: 4-Way Onion",
      "unit": "Serving",
      "p": 48,
      "f": 41,
      "c": 58,
      "_id": "512ae0c67fdfe7e44900003d",
      "__v": 0
    }, {
      "name": "Skyline: Cheese Coney",
      "unit": "Serving",
      "p": 20,
      "f": 23,
      "c": 24,
      "_id": "512ae0c67fdfe7e44900003e",
      "__v": 0
    }, {
      "name": "Skyline: Chili Cheese Sandwich",
      "unit": "Serving",
      "p": 20,
      "f": 18,
      "c": 24,
      "_id": "512ae0c67fdfe7e44900003f",
      "__v": 0
    }, {
      "name": "Spinach (Raw)",
      "unit": "100g",
      "p": 3,
      "f": 0,
      "c": 4,
      "_id": "512ae0c67fdfe7e449000040",
      "__v": 0
    }, {
      "name": "Starbucks Grande 2% Latte",
      "unit": "Serving",
      "p": 12,
      "f": 7,
      "c": 18,
      "_id": "512ae0c67fdfe7e449000041",
      "__v": 0
    }, {
      "name": "Starbucks Grande 2% Mocha",
      "unit": "Serving",
      "p": 13,
      "f": 8,
      "c": 42,
      "_id": "512ae0c67fdfe7e449000042",
      "__v": 0
    }, {
      "name": "Starbucks Grande Nonfat Latte",
      "unit": "Serving",
      "p": 13,
      "f": 0,
      "c": 19,
      "_id": "512ae0c67fdfe7e449000043",
      "__v": 0
    }, {
      "name": "Starbucks Grande Nonfat Mocha",
      "unit": "Serving",
      "p": 13,
      "f": 2.5,
      "c": 43,
      "_id": "512ae0c67fdfe7e449000044",
      "__v": 0
    }, {
      "name": "Starbucks Iced Grande 2% Mocha",
      "unit": "Serving",
      "p": 9,
      "f": 6,
      "c": 36,
      "_id": "512ae0c67fdfe7e449000045",
      "__v": 0
    }, {
      "name": "Starbucks Iced Grande Nonfat Mocha",
      "unit": "Serving",
      "p": 9,
      "f": 2.5,
      "c": 37,
      "_id": "512ae0c67fdfe7e449000046",
      "__v": 0
    }, {
      "name": "Strawberries",
      "unit": "Cup",
      "p": 1,
      "f": 0,
      "c": 12,
      "_id": "512ae0c67fdfe7e449000047",
      "__v": 0
    }, {
      "name": "Sweet Potato - Mashed",
      "unit": "Cup",
      "p": 4,
      "f": 0,
      "c": 42,
      "_id": "512ae0c67fdfe7e449000048",
      "__v": 0
    }, {
      "name": "Target 1% Cottage Cheese",
      "unit": "Cup",
      "p": 22,
      "f": 2,
      "c": 12,
      "_id": "512ae0c67fdfe7e449000049",
      "__v": 0
    }, {
      "name": "Target Honey Ham",
      "unit": "Ounce",
      "p": 5,
      "f": 0.75,
      "c": 1.5,
      "_id": "512ae0c67fdfe7e44900004a",
      "__v": 0
    }, {
      "name": "Thomas' English Muffin",
      "unit": "Serving",
      "p": 4,
      "f": 1,
      "c": 25,
      "_id": "512ae0c67fdfe7e44900004b",
      "__v": 0
    }, {
      "name": "Turkey Bacon",
      "unit": "Slice",
      "p": 2,
      "f": 0,
      "c": 2,
      "_id": "512ae0c67fdfe7e44900004c",
      "__v": 0
    }, {
      "name": "White Castle: Bacon, Egg & Cheese Sandwich",
      "unit": "Serving",
      "p": 12,
      "f": 12,
      "c": 13,
      "_id": "512ae0c67fdfe7e44900004d",
      "__v": 0
    }, {
      "name": "White Castle: Cheese Stick",
      "unit": "Stick",
      "p": 4,
      "f": 11,
      "c": 7,
      "_id": "512ae0c67fdfe7e44900004e",
      "__v": 0
    }, {
      "name": "White Castle: Cheeseburger",
      "unit": "Serving",
      "p": 8,
      "f": 9,
      "c": 15,
      "_id": "512ae0c67fdfe7e44900004f",
      "__v": 0
    }, {
      "name": "White Castle: Egg & Cheese Sandwich",
      "unit": "Serving",
      "p": 9,
      "f": 7,
      "c": 13,
      "_id": "512ae0c67fdfe7e449000050",
      "__v": 0
    }, {
      "name": "White Castle: Hash Rounds (Small)",
      "unit": "Serving",
      "p": 2,
      "f": 4,
      "c": 25,
      "_id": "512ae0c67fdfe7e449000051",
      "__v": 0
    }, {
      "name": "Wholly Guacamole",
      "unit": "Tbsp",
      "p": 0.5,
      "f": 2.5,
      "c": 1.5,
      "_id": "512ae0c67fdfe7e449000052",
      "__v": 0
    }];
   
    (function() {
      var initializing = false,
          fnTest = /xyz/.test(function() {
          xyz;
        }) ? /\b_super\b/ : /.*/;
   
      // The base Class implementation (does nothing)
      this.Class = function() {};
   
      // Create a new Class that inherits from this class
      Class.extend = function(prop) {
        var _super = this.prototype;
   
        // Instantiate a base class (but only create the instance,
        // don't run the init constructor)
        initializing = true;
        var prototype = new this();
        initializing = false;
   
        // Copy the properties over onto the new prototype
        for (var name in prop) {
          // Check if we're overwriting an existing function
          prototype[name] = typeof prop[name] == "function" && typeof _super[name] == "function" && fnTest.test(prop[name]) ? (function(name, fn) {
            return function() {
              var tmp = this._super;
   
              // Add a new ._super() method that is the same method
              // but on the super-class
              this._super = _super[name];
   
              // The method only need to be bound temporarily, so we
              // remove it when we're done executing
              var ret = fn.apply(this, arguments);
              this._super = tmp;
   
              return ret;
            };
          })(name, prop[name]) : prop[name];
        }
   
        // The dummy class constructor
   
        function Class() {
          // All construction is actually done in the init method
          if (!initializing && this.init) this.init.apply(this, arguments);
        }
   
        // Populate our constructed prototype object
        Class.prototype = prototype;
   
        // Enforce the constructor to be what we expect
        Class.prototype.constructor = Class;
   
        // And make this class extendable
        Class.extend = arguments.callee;
   
        return Class;
      };
    })();
   
    (function() {
   
      Type = function(child) {
        this._child = child;
        this._child.prototype.merge = function(src, overwrite) {
          for (var prop in src) {
            if (overwrite || !this.hasOwnProperty(prop)) {
              this[prop] = src[prop];
            }
          }
          return this;
        };
   
        this.extend = function(parent) {
          this._child.prototype = new parent;
          return this;
        }
   
        this.from = function(obj) {
          for (var prop in obj) {
            if (this._child.prototype[prop]) {
              this._child.prototype['_' + prop] = this._child.prototype[prop];
            }
            this._child.prototype[prop] = obj[prop];
          }
   
          return this._child;
        }
   
        return this;
      };
   
    })();
   
    var FirstClass = Class.extend({
   
      init: function() {
        return 'FirstClass init';
      },
   
      name: null,
      unit: null,
      p: null,
      f: null,
      c: null
   
    });
   
    var SecondClass = FirstClass.extend({
      init: function() {
        return 'SecondClass ' + this._super();
      }
    });
   
    var ThirdClass = SecondClass.extend({
      init: function() {
        return 'ThirdClass ' + this._super();
      }
    });
   
    var FourthClass = ThirdClass.extend({
      init: function() {
        return 'FourthClass ' + this._super();
      }
    });
   
    var FirstType = Type(function FirstType() {
      return 'FirstType ctor';
    }).from({
   
      name: null,
      unit: null,
      p: null,
      f: null,
      c: null
   
    });
   
    var SecondType = Type(function SecondType() {
      return 'SecondType ' + this.constructor.apply(this, arguments);
    }).extend(FirstType).from({});
   
    var ThirdType = Type(function ThirdType() {
      return 'ThirdType ' + this.constructor.apply(this, arguments);
    }).extend(SecondType).from({});
   
    var FourthType = Type(function FourthType() {
      return 'FourthType ' + this.constructor.apply(this, arguments);
    }).extend(ThirdType).from({});
};

Benchmark.prototype.teardown = function() {
    data = Class = Type = null;
    FirstClass = SecondClass = ThirdClass = FourthClass = null;
    FirstType = SecondType = ThirdType = FourthType = null;
};
</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
FirstClass
for (var i = 0; i < data.length; i++) {
  var food = _.extend(new FirstClass(), data[i]);
}
pending…
SecondClass
for (var i = 0; i < data.length; i++) {
  var food = _.extend(new SecondClass(), data[i]);
}
pending…
ThirdClass
for (var i = 0; i < data.length; i++) {
  var food = _.extend(new ThirdClass(), data[i]);
}
pending…
FourthClass
for (var i = 0; i < data.length; i++) {
  var food = _.extend(new FourthClass(), data[i]);
}
pending…
FirstType
for (var i = 0; i < data.length; i++) {
  var food = new FirstType().merge(data[i]);
}
pending…
SecondType
for (var i = 0; i < data.length; i++) {
  var food = new SecondType().merge(data[i]);
}
pending…
ThirdType
for (var i = 0; i < data.length; i++) {
  var food = new ThirdType().merge(data[i]);
}
pending…
FourthType
for (var i = 0; i < data.length; i++) {
  var food = new FourthType().merge(data[i]);
}
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