Simple prototypal inheritance
From Trephine
| « Adventures in Rhino - setters and getters | » |
[subscribe] Recent blog entries
- Simple prototypal inheritance new!
- Adventures in Rhino - setters and getters
- Site improvements - fighting with Disqus
- JavaScript task chaining
- JavaScript string building benchmarks
- Efficient JavaScript string building
- Alternative JavaScript worker thread API
- Implementing JavaScript worker threads
- Thread safe DOM manipulation
- Site improvements - CSS sprites
- Trephine worker threads made easy
- Pitfalls of multithreaded browser development
- Site improvements - reducing dependencies
- The unsplittability of XML
Live Demos
Simple prototypal inheritance
JavaScript has a beautiful prototypal inheritance mechanism. Unfortunately, the language's "new" operator and the prototype property make it a bit confusing to write code which leverages it. This article demonstrates one way to simplify the creation of JavaScript prototypal inheritance chains by eliminating the need for a constructor function.
To start, consider this snippet, found on Douglas Crockford's article Prototypal Inheritance in JavaScript:
if (typeof Object.create !== 'function') { Object.create = function (o) { function F() {} F.prototype = o; return new F(); }; }
Although the code may seem somewhat cryptic, Crockford's create function is actually a very elegant approach to simplifying prototypal inheritance in JavaScript.
Here's an example of how it would be used:
// Define the Prototype var Person = { greet: function() { alert("Hello, I'm " + this.name); } }; // Create instance inheriting from the prototype var bob = Object.create(Person); bob.name = "Bob"; bob.greet(); // Alerts "Hello, I'm Bob"
I like this approach because it does away with a lot of the concern about [[ Understanding the JavaScript new keyword|the "new" operator]], which can be a bit abstruse. With object.create, you don't have to worry about creating a constructor function off of which to base your prototype - it's simply a matter of defining the inheritance chain.
Setting properties on newly created objects will be quite common if you choose to follow this model. Take bob for example - the first thing we do after creating the object is to set bob.name to "Bob". It would be nice to be able to set properties during the call to create() "all at once", instead of assigning them separately.
Here is my simple prototype inheritance implementation, heavily commented to explain what's going on:
Object.create = (function(){ // closure to create scope var anonymous = function(){}; // anonymous function to create objects return function create(prototype, opt) { // define and return the "create" func anonymous.prototype = prototype; // establish prototypal inheritance var object = new anonymous(); // create the new object if (typeof opt!=="object") return object; // short-circuit if no options var has = Object.prototype.hasOwnProperty; // reference to canonical property test for (var k in opt) { // loop over option keys if (has.call(opt, k)) { // if the key belongs to the object object[k] = opt[k]; // duplicate the property } } return object; // return the new object }; })(); // end scoping closure
Notice that Object.create appears only at the beginning. It would be simple to change it to something else, for example if you wanted to make the create function a part of your own library.
Using the above, we can rewrite the previous Bob example as follows:
var bob = Object.create(Person, {name: "Bob"}); bob.greet(); // Alerts "Hello, I'm Bob"
It also makes creating Prototype chains cleaner, for example:
// Define the Person prototype (same as above) var Person = { greet: function() { alert("Hello, I'm " + this.name); } }; // Define the Employee prototype (extends Person) var Employee = Object.create(Person, { status: function() { alert("I'm " + this.name + ", the " + this.title); } }); // Create instances inheriting from the prototypes var alice = Object.create(Person, {name: "Alice"}); var bob = Object.create(Employee, {name: "Bob", title: "grunt"}); alice.greet(); // Alerts "Hello, I'm Alice" bob.greet(); // Alerts "Hello, I'm Bob" bob.status(); // Alerts "I'm Bob the grunt"
As you can see, this approach makes it easy to create arbitrarily deep inheritance chains with little overhead code.
If this helped you, or if you have any questions, please leave a comment. Thanks!
Public domain declaration
Just so there's no confusion: all of the code snippets on this page are provided "AS IS", without warranty of any kind, express or implied.
All of the code snippets on this page are hereby released into the public domain by the me, the copyright holder. This applies worldwide. Or in case this is not legally possible: The copyright holder grants any entity the right to use this work for any purpose, without any conditions, unless such conditions are required by law.
If you'd feel better with a "real" license, you're free to use code snippets on this page under the MIT license as described on the about page.
Any links back to this site are always appreciated, but not required. Enjoy!
--Jim R. Wilson (jimbojw) 14:10, 5 October 2009 (UTC)