Editing Type.js versus Class.js This edit will create a new revision. Your details (optional) Name Email (won’t be displayed; might be used for Gravatar) URL Test case details Title * Published (uncheck if you want to fiddle around before making the page public) Description (in case you feel further explanation is needed)(Markdown syntax is allowed) 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. Are you a spammer? (just answer the question) Preparation code Preparation code HTML (this will be inserted in the <body> of a valid HTML5 document in standards mode) (useful when testing DOM operations or including libraries) <script src="//cdnjs.cloudflare.com/ajax/libs/lodash.js/1.0.1/lodash.min.js"> </script> Include JavaScript libraries as follows: <script src="//cdn.ext/library.js"></script> Define setup for all tests (variables, functions, arrays or other objects that will be used in the tests) (runs before each clocked test loop, outside of the timed code region) (e.g. define local test variables, reset global variables, clear canvas, etc.) (see FAQ) 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) { var src, i; if (typeof parent === 'function') { this._child.prototype = new parent; i = 1; } else { i = 0; } for (i; i < arguments.length; i++) { this.from(arguments[i]); } return this._child; } 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'; }).extend({ name: null, unit: null, p: null, f: null, c: null }); var SecondType = Type(function SecondType() { return 'SecondType ' + this.constructor.apply(this, arguments); }).extend(FirstType, {}); var ThirdType = Type(function ThirdType() { return 'ThirdType ' + this.constructor.apply(this, arguments); }).extend(SecondType, {}); var FourthType = Type(function FourthType() { return 'FourthType ' + this.constructor.apply(this, arguments); }).extend(ThirdType, {}); Define teardown for all tests (runs after each clocked test loop, outside of the timed code region) (see FAQ) data = Class = Type = null; FirstClass = SecondClass = ThirdClass = FourthClass = null; FirstType = SecondType = ThirdType = FourthType = null; Code snippets to compare Test 1 Title Async (check if this is an asynchronous test) Code for (var i = 0; i < data.length; i++) { var food = _.extend(new FirstClass(), data[i]); } Test 2 Title Async (check if this is an asynchronous test) Code for (var i = 0; i < data.length; i++) { var food = _.extend(new SecondClass(), data[i]); } Test 3 Title Async (check if this is an asynchronous test) Code for (var i = 0; i < data.length; i++) { var food = _.extend(new ThirdClass(), data[i]); } Test 4 Title Async (check if this is an asynchronous test) Code for (var i = 0; i < data.length; i++) { var food = _.extend(new FourthClass(), data[i]); } Test 5 Title Async (check if this is an asynchronous test) Code for (var i = 0; i < data.length; i++) { var food = new FirstType().merge(data[i]); } Test 6 Title Async (check if this is an asynchronous test) Code for (var i = 0; i < data.length; i++) { var food = new SecondType().merge(data[i]); } Test 7 Title Async (check if this is an asynchronous test) Code for (var i = 0; i < data.length; i++) { var food = new ThirdType().merge(data[i]); } Test 8 Title Async (check if this is an asynchronous test) Code for (var i = 0; i < data.length; i++) { var food = new FourthType().merge(data[i]); }