BeardsAndFlannels, CA 94103

T3h blog

Prototype Chains and Object Delegation in JavaScript
November 13th, 2014

When searching for a property in an object, JavaScript goes through a process where it searches for the property in question, naturally, in the object itself. But what happens if the object doesn't possess the property we're looking for? Here's what's going on under the hood.

Every object in JavaScript has an internal link to another object known as its prototype. Each object has exactly one prototype. If the search fails to find the property in an object, the search will move up to that object's prototype and check there. This process continues on up through each prototype's prototype until either the property is found or the search has gone through the entire series of linked prototypes. This series of linked prototype objects is known as the prototype chain. If the property is found somewhere along the prototype chain, we get our property returned to us, almost as if the original object we searched possessed the property all along.

The final object in any prototype chain has null as its prototype. null, being a primitive value, is one of the few types in JavaScript that is not an object and by definition, cannot have a prototype. The final object that has null as its prototype is by default known as "THE object prototype", (emphasis on "THE" so as not to be confused with the more generic objects and prototypes I was referring to in the beginning of this blog post.

If the search for the property reaches a null value, we get a value of undefined returned to us. This process of directing a property search to move up the prototype chain upon failing to find a property is called delegation, where each object delegates to its prototype.

Let's take a look at this in code. The method we'll use to create new objects and establish the prototypal relationship(s) below is Object.create. The first argument passed into Object.create's parameters will be the prototype for the newly-created object. A second argument can be passed into this method to add properties onto the newly-created object upon creation, but we won't concern ourselves with that here.

var car;
var mustang;

var vehicle = {
moves: true,
hasSeats: true

//The object that the variable car points to is created
//and vehicle is set as its prototype
car = Object.create(vehicle);
car.wheels = 4;
car.doors = 2;

//The object that the variable mustang points to is created
//and car is set as its prototype
mustang = Object.create(car)
mustang.color = "blue";
mustang.cylinders = 8;

//Let's see what shows up on some searches

mustang.color // "blue"
mustang.wheels // 4
mustang.hasSeats // true
mustang.hasSunRoof //undefined

The ability for a lower level object to access properties higher up the prototype chain is called prototypal inheritance, and is one of the defining features of the JavaScript language in general. It's important to keep in mind that the variable names we assign to objects are just that - names. They aren't the objects themselves. If after the code above we re-assigned the variable name mustang to a different object that delegated to a different prototype, the object mustang used to point to, the one with a "color" value of "blue" and a prototype object assigned to car, would remain unchanged. The name mustang would simply point to a new object. To get a better visual on how the object mustang originally pointed to doesn't change, I'll assigned a new variable name to that object before re-assigning mustang to a different one. Here's some code to look at:

//assigns new variable name, not to mustang, but to the object that mustang is currently pointing to
var camaro = mustang;

mustang; // Object {color: "blue", cylinders: 8, wheels: 4, doors: 2, moves: true, hasSeats: true}
camaro; // Object {color: "blue", cylinders: 8, wheels: 4, doors: 2, moves: true, hasSeats: true}

var horse = {
legs: 4,
hasTail: true

mustang = Object.create(horse);
mustang; // Object {legs: 4, hasTail: true}
camaro; // Object {color: "blue", cylinders: 8, wheels: 4, doors: 2, moves: true, hasSeats: true}

Looking at the objects mustang and camaro are most recently pointing to, it's easy at first glance to think that all of the properties shown are immediately contained in them. But now we know that mustang for instance, had to delegate to its prototype horse before we could see the "legs" and "hasTail" values. Object.create is creating and returning a brand new object when it's called. Part of that creation process is establishing the prototype of the newly-created object and as a result, you cannot change what the new object delegates to later*.

*The constructor.prototype and ._proto_ features provide ways for the prototype of an object to be mutated after the creation of an object. However, for ECMAScript 5 these are non-standard features and the use of them in code is typically discouraged. ._proto_ is included the Ecma-262 Edition 6, but for now ECMAScript 5 standards should probably not be ignored.

Back to Blog Summaries