Prototype Chains are a mechanism for making objects that resemble other objects.
When we want to have two objects that have all the same properties, the naive approach would be to copy all properties of one object into the other. Using prototype chains, on the other hand, makes one object behave as though it has all the properties of another by delegating failed property lookups to the other object at lookup time.
How to Create Prototype Chains
The Object.create(proto [, propertiesObject])
static method will make a prototype chain for us.
An important benefit of this method is that failed property lookups are delegated at lookup-time, whereas a one-time property copy utility function will only clone properties at copy-time. Any new properties added to the prototype object will be accessible via fall-through by objects created with Object.create
.
Prototypal Classes
Transform this:
var Car = function (loc) {
var obj = { loc: loc };
_.extend(obj, Car.methods);
return obj;
};
Car.methods = {
move: function () { this.loc++; };
};
into this:
var Car = function (loc) {
var obj = Object.create(Car.prototype);
obj.loc = loc;
return obj;
};
Car.prototype.move = function () { this.loc++; };
This establishes a prototype chain (_.extend
replaced with Object.create
) and assigns loc
directly. Each instance of Car now has access to properties and methods of the parent class, Car, without having to copy them individually at instantiation.
Note about using the term prototype
If someone says “obj1
’s prototype is obj2
,” a reasonable interpretation would be to think that failed lookups on obj1
would fall through to obj2
. This is true if obj1
is an instance created from a prototypal obj2
class. This interpretation is not true of the relationship the class itself has to the prototype.
A class is declared using a function object, and failed property lookups on it will fall through to Function.prototype
! In the example above, Car is a function object, and it’s prototype is Function.prototype
.
And yet, when Car
runs, it will create objects that delegate failed lookups to Car.prototype
. In that sense, you might say that Car’s prototype is Car.prototype
. The nomenclature is confusing and ambiguous.
Saying that an instance prototype is obj.prototype
means something different from saying that a class prototype is obj.prototype
, yet both can be true statements!