Created
April 30, 2012 06:14
-
-
Save cjohansen/2555903 to your computer and use it in GitHub Desktop.
Using Object create as alternative to constructors
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Example based on the one from Isaac's inherits: https://github.com/isaacs/inherits | |
var animal = { | |
create: function (name) { | |
return Object.create(this, { name: { value: name, enumerable: true } }); | |
}, | |
alive: true, | |
say: function (what) { | |
console.log(this.name + " says " + what); | |
} | |
}; | |
// Create an animal | |
var pet = animal.create("Biggles"); | |
pet.say("D'OH!"); // "Biggles says D'OH!" | |
// To build the prototype chain we only want object allocation, | |
// no initialization, so we use Object.create rather than | |
// animal.create() | |
var dog = Object.create(animal, { | |
sniff: { value: function () { | |
this.say("sniff sniff") | |
}, | |
bark: { value: function () { | |
this.say("woof woof") | |
} | |
}; | |
// Create a dog | |
var pet = dog.create("Doug"); | |
pet.bark(); // "Doug says woof woof" | |
// If you're worried about performance, you might not want to use | |
// native Object.create, as it's pretty slow (at least with V8 last I | |
// checked). Let's provide a simple shim. | |
// Property descriptors are very verbose, and mostly not needed. | |
// Given a simple property-by-property extend function we could simplify. | |
var create = (function () { | |
function F() {} | |
return function (object) { | |
F.prototype = object; | |
return new F(); | |
}; | |
}()); | |
// Simplified | |
var extend = function() { | |
var target = {}; | |
for (var i = 0, l = arguments.length; i < l; ++i) { | |
for (var prop in arguments[i]) { | |
if (arguments[i].hasOwnProperty(prop)) { | |
target[prop] = arguments[i][prop]; | |
} | |
} | |
} | |
return target; | |
}; | |
var animal = { | |
create: function (name) { | |
return extend(create(this), { name: name }); | |
}, | |
alive: true, | |
say: function (what) { | |
console.log(this.name + " says " + what); | |
} | |
}; | |
var dog = extend(create(animal), { | |
sniff: function () { | |
this.say("sniff sniff") | |
}, | |
bark: function () { | |
this.say("woof woof") | |
} | |
}; | |
// This whole thing was sparked by Peter Michaux' (valid) criticism that | |
// constructors don't go well with map: https://gist.github.com/2552304 | |
// The create function resembles Peter's Function.prototype.new, except | |
// it forgoes the constructor concept entirely. It works with map the | |
// same way: | |
// Not a constructor, so lower cased first letter | |
var todoView = { | |
create: function (options) { | |
return extend(create(this), { // Inheritance friendly | |
/* ... */ | |
}); | |
} | |
}; | |
var todoViews = todoModels.map(todoView.create, todoView); | |
// We could get around passing in the this argument, but then we'd have | |
// to hard-code todoView.create to todoView, meaning it must be overridden | |
// in inheriting objects, which again means it will be really hard to | |
// make inheriting objects call "super" on create. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment