Simple prototypal inheritance

From Trephine

Jump to: navigation, search
« Adventures in Rhino - setters and getters »

[subscribe] Recent blog entries

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)