Understanding Inheritance In JavaScript
In this article I will present the JavaScript inerhitence model in a concise, and I hope, easy to understand manner. The intended audience consists of developers with some previous experience with dynamically typed languages. It is my opinion that any difficulty associated with understanding the JavaScript inheritance model can be attributed to the difficulty teaching recursive definitions in general. It's sometimes hard to know where to start, when your definition is circular.
That said, let's boil JavaScript inheritance down into 5 key points in the following order:
1) In JavaScript, everything is an 'object' and all variables simply hold references to them. The other 'primitive' or basic types (of objects) are functions, booleans, strings, numbers and arrays.
2) Objects are collections of properties keyed by a reference. Most often, references to string objects are used as keys as they are immutable. This means that if foo and bar reference string types which contain the same data they are in fact the same object. This essentially makes Objects equivalent to hashes or dictionaries in other languages.
3) In JavaScript functions are special objects. Not only can they be called or applied, they have a special 'prototype' property which holds an object that can be accessed and modified. When a function is used as a constructor with the 'new' key word, the resulting object that is created will *dynamically* inherit from the object referenced by the constructor function's 'prototype' property.
Example:
Constructor = function() { };
Constructor.prototype.name = 'alpha';
Constructor.prototype.say_name = function() { console.log("my name is: " + this.name) };
object = new Constructor();
object.say_name();
4) Upon initial definition, the prototype property of every new function can be thought of like this:
func = function() {}
func.prototype = { 'constructor': func };
That is, the value referenced by func.prototype is an object contains a reference to func itself. This recursive definition is a bit eye-crossing but actually very beautiful in that way that only recursion can be.
5) Here's where the recursive definitions start to get difficult to visualize. In JavaScript, every object (including functions) dynamically inherit from the special 'Object.prototype' object. In other words, 'Object' is THE constructor function of ALL objects in the JavaScript universe. The corollary being that Object.prototype.constructor == Object.
Try it:
> Object.prototype.constructor == Object
true
Implications
These 4 points form the foundation of inheritance in JavaScript. Let's make use what we've learned:
Corollary 1:
Object types, or 'classes' can be (and generally are) referred to by their contructor function. Examples: Object, Function, String, Boolean, Array etc.
Corollary 2:
If you want to add a method to every object in the javascript universe (even after it is constructed!), mess with Object.prototype.
Example:
> Object.prototype.foo = 'bar'
> func = function() {}
> func.foo
"bar"
> Object.prototype.foo = 'baz'
> func.foo
"baz"
Corollary 3:
There's no such thing as multiple inheritance in JavaScript. That is class 'Foo' can not inherit from both 'String' and 'Array' directly. Though, you can use some clever tricks to hack multiple inheritance into the language. For examples, see http://www.amirharel.com/2010/06/11/implementing-multiple-inheritance-in-javascript and http://code.google.com/p/joose-js/.