Chain, chain, chain… chain of OLOOs..

JavaScript Object Creation and the Prototype Chain

When learning JavaScript, one of the concepts that can be a bit tricky to clearly understand at first is the way in which we can create custom objects to form a prototype chain. It certainly took me a little while to wrap my head around, and I think one of the main reasons for this is that most object-creation patterns used within JavaScript try to enforce a paradigm that simply isn’t natural to the language.

JavaScript doesn’t have ‘classes’, but when we use JavaScript in an object-oriented way we can tend to fall back on mental-models for ‘inheritance’ that are familiar from object-oriented languages which are class-based. While JavaScript can (and often is) used with this paradigm in mind, it has the effect of obfuscating what’s actually happening in terms of the object relationships in our code. This way of using JavaScript can also have the knock-on effect of creating a steeper learning curve for beginners by promoting unecessarily complex mental models.

In this article I’m going to discuss JavaScript’s prototype chain, look at how it works, examine how constructors are traditionally used to create a prototype chain, and then compare this to the OLOO approach which simplifies things by removing the need for constructors altogether.

This article does assume that readers have some existing knowledge of JavaScript objects, however it may be useful to start with a brief recap of some basics before we get into the complexities of constructors and prototypes.


Objects

Objects in JavaScript are a compound data type, in that they are made up of other data. That other data is represented in the object as the values of the object’s properties. These values can be primitives or other objects. When the values are function objects they are generally referred to as the object’s methods.

We can create custom objects using an object literal, defining its properties within the literal notation:

var myObj = {
a: 1,
b: [1, 2, 3],
c: function() { return this },
};

When we call a method on an object, the execution context (this) for that function is the object itself:

myObj.c() === myObj; // true

There are a number of standard built-in objects already available within the JavaScript environment. We can reference these objects, access their properties, and call their methods.

typeof Math === 'object'; // true
Math.PI; // 3.141592653589793
Math.sqrt(16); // 4

The Prototype Chain

JavaScript has a concept called the prototype chain. This is where one object can act as a ‘prototype’ for other objects further down the ‘chain’.

This allows us to define behaviours on the ‘prototype’ object and have all the objects down the chain access those behaviours.

The reason this works is because of JavaScript’s behaviour delegation. What this means is that if you call a method on an object, JavaScript will first try to find a matching property for that method on the object itself; if the object has no such property, then JavaScript will then look in the object’s ‘prototype’ object for that property, in effect ‘delegating’ the method call to the prototype object.

It doesn’t have to stop there though. A prototype object can have its own prototype object, and so on, creating a ‘chain’ of objects known as the ‘prototype chain’. JavaScript will continue delegating up the chain until it either finds the property or reaches the end of the chain.

You might be wondering how this chain is ‘linked together’. Let’s look at that next.

The [[Prototype]] property

All objects have a property called [[Prototype]]. The value of this property is another object, the object's 'prototype object'.

[[Prototype]] is an 'internal' property, and isn't a property you can directly interact with in the normal way (i.e. via dot notation or bracket notation).

myObj = {};
myObj.[[Prototype]]; // SyntaxError: Unexpected token [
myObj['[[Prototype]]']; // undefined

It is possible to access the value of this property in a couple of ways:

  • __proto__. This is a accessor method for an object's [[Prototype]] property. It was never officially part of the language specification. It has been standardized as a legacy feature in ES6, but is deprecated and has been removed from the Web Standards. I wouldn't recommend using it in production code.
  • Object.getPrototypeOf(). This is a method of the built-in Object object. It takes an object as an argument and returns the value of that object's [[Prototype]] property.

Ok, so we know that all objects have this [[Prototype]] property, and that it can be used to link together objects to create a 'prototype chain', but how does the [[Prototype]] property get assigned to the 'prototype' object?

One way to do this is to use a constructor.

Constructors

Before we explain how constructors work with the prototype chain, we’ll find out a bit more about them and look at why they get used.

Remember that JavaScript has a number of ‘built-in’ objects. Well, many of these built-in objects are also constructors. What this means is that they can be used to create other objects.

Constructors are usually executed with the new operator.

var myDate = new Date('01/01/2001');
var myRegex = new RegExp('\\w+');

When we create an object with a constructor, it has access to a property named constructor which references the constructor which created the object. (Note: this property doesn't belong to the created object itself, but to its [[Prototype]]object; don't worry about what this means for now, we'll look at it in more detail later).

myDate.constructor === Date; // true
myRegex.constructor == RegExp; // true

Most of these built in constructors (Date being one exception) are what is known as 'scope-safe'. This means you can call them without using the new operator and the result will be the same.

var myRegex = RegExp('\\w+');
myRegex.constructor == RegExp; // true

Custom constructors aren’t automatically scope-safe, which we’ll look at a bit later on.

Object

JavaScript’s built-in Object object is also a constructor.

var myObj = new Object;
myObj.constructor == Object; // true

When we created an object earlier using the object literal syntax, we were using the initialiser notation for Object.

var someObj = {};
var anotherObj = new Object;

Other than some negligible performance differences, there’s no functional difference in the way we created the two objects in the above example. (Note that we’re specifically talking about new Object vs {} here; for primitives there is a functional difference between the literal and constructor notation, which we won't go into here).

You can also create objects using the Object.create() method, which we'll look at when discussing the OLOO object creation pattern.

Why use constructors?

Given that there’s no real functional difference between the literal syntax and constructor notation when creating objects, why use a constructor at all? Well, constructors can come in useful when creating lots of custom objects of the same ‘type’.

Say for example we wanted to create a number of objects that represent animals. Our animal objects all have the same properties such as name, age, and species. We could use literal notation to do this.

rex = {
name: 'Rex',
age: 4,
species: 'dog',
}
paws = {
name: 'Paws',
age: 11,
species: 'cat',
}
fluffy = {
name: 'Fluffy',
age: 2,
species: 'rabbit',
}

As you can see, there’s a lot of repetition in our code; we have to define the properties on each of our objects. It would be a lot easier if the properties were already defined and we just needed to set the values.

rex = new Animal('Rex', 4, 'dog');
paws = new Animal('Paws', 11, 'cat');
fluffy = new Animal('Fluffy', 2, 'rabbit');

In fact, we can do this by using a custom constructor, also known as a constructor function.

When you declare a function you create a function object. That function object is automatically a constructor. This means that when we call the function with the new operator, it creates an object.

function myFunc() {};
var myObj = new myFunc;
myObj.constructor === myFunc; // true

If you’ve never seen functions used as constructors before, the above code may seem a little strange. Let’s break it down.

On line 1, we declare a function called myFunc. As we've already mentioned, functions in JavaScript are automatically constructors.

On line 2, we declare a variable, myObj, and assign it to the return value of new myFunc (i.e. calling myFunc with the newoperator). Let's look in a bit more detail at what is happening with that function call. When new myFunc is executed, the following things happen:

  1. A new object is created
  2. The myFunc function is called, with the execution context of that function call (i.e. this) being the newly created object, (since this the function body is empty, that isn't particularly relevant to this example).
  3. The newly created object is returned.

On line 3, we check that the value of constructor for myObj is in fact myFunc. As previously mentioned, constructor is not a direct property of myObj, but is available to it via its prototype chain.

Defining Attributes

Since the function body of myFunc is empty, the returned object is just an empty object with no properties. Let's use our Animal example from earlier to see how we can define properties using a custom constructor.

function Animal(name, age, species) {
this.name = name;
this.age = age;
this.species = species;
}
rex = new Animal('Rex', 4, 'dog');
paws = new Animal('Paws', 11, 'cat');
fluffy = new Animal('Fluffy', 2, 'rabbit');
rex.name; // 'Rex'
paws.age; // 11
fluffy.species; // 'rabbit'
rex.constructor === Animal; // true
paws.constructor === Animal; // true
fluffy.constructor === Animal; // true
  • When new Animal is executed, a new object is created and then the Animal function called with that object as the execution context, i.e. this.
  • The body of the function defines properties on that newly created object (this), with the function arguments set as the values.
  • Finally the newly created object is returned and assigned to our variables rex, paws, and fluffy. (Note that the capitalisation of our function name, Animal, is just a convention when defining a function to be used as a constructor, rather than a syntactical requirement).

Scope Safe Constructors

Remember we said that the ‘built-in’ JavaScript constructors were ‘scope-safe’; in other words they could be called without the new operator? This isn't the case for custom constructors like our Animal function. If we call the function without new, then a new object is not created and the execution context of the function (this) is the global object (which is window in a browser environment), so the properties are created on the global object rather than a new object. Additionally, the function implicitly returns undefined rather than a new object, so our variable is assigned to undefined instead of a new Animalobject.

goldie = Animal('Goldie', 1, 'goldfish');
goldie; // undefined
window.name; // 'Goldie'
window.age; // 1
window.species; // 'goldfish'

Calling a constructor function without new is a common source of bugs in JavaScript programs, and one of the reasons some developers don't like using constructors to create objects.

It is possible to make a custom constructor scope-safe by checking if a new object was created (i.e. this is an instance of the constructor) and using that in a conditional:

function Animal(name, age, species) {
if (this instanceof Animal){
this.name = name;
this.age = age;
this.species = species;
} else {
return new Animal(name, age, species);
}
}

Sharing Behaviour

So we’ve seen that constructors are useful for creating attributes on multiple objects of the same type by defining properties for those objects in the constructor function. Each of the objects we create has its own value for those properties. If we want all of our custom objects to have access to a particular function, then we’d need to define a property whose value was that same function for all of the objects we create.

function Animal(name, age, species) {
this.name = name;
this.age = age;
this.species = species;
this.move = function() {
console.log(this.name + ' is walking.');
};
}

rex = new Animal('Rex', 4, 'dog');
paws = new Animal('Paws', 11, 'cat');

That function can now be called as a method on our created objects.

rex.move(); // 'Rex is walking.'
paws.move(); // 'Paws is walking.'

That seems like a good way of sharing behaviour between objects, but something to be aware of is that the objects receive a copy of the function assigned to their own move property. If, for example, we want to change our move function after creating the objects, we'd need to update each object individually to change the value of the property.

rex.move = function() {
console.log(this.name + ' is running.');
};
rex.move(); // 'Rex is running.'
paws.move(); // 'Paws is walking.'
paws.move = function() {
console.log(this.name + ' is running.');
};
paws.move(); // 'Paws is running.'

If we had a lot of objects, this would get pretty tedious. It would be great if we could define a function in such a way that multiple objects can access it without having to create their own copies of it. Well, we can do that by using JavaScript’s behaviour delegation. We’ll look at how to do this next.

Constructors and the Prototype Chain

Earlier on we looked at how all objects have a [[Prototype]] property, and how the value of this property is another object. We saw how you can have a series of objects, each linked to the next one by their [[Prototype]] property, form a 'prototype chain'.

We also said that one way to assign the [[Prototype]] property of an object is to use a constructor. So how does this happen? When constructors create an object, they set the value of that new object's [[Prototype]] property to the same object as their own prototype property.

Wait, what?

The prototype property

All constructors have a property called prototype. The value of this property is another object, the constructor's 'object prototype'. This is where it can get confusing.

Although [[Prototype]] and prototype sound the same, they are in fact different properties. We've already said that all objects have the internal [[Prototype]] property; the same is not true of prototype, only constructors have this property. Like the [[Prototype]] property, prototype also points to an object; constructors set this object as the value of the [[Prototype]] property for any objects that they create.

From the diagram above we can see that the prototype property of the MyFunc constructor points to the same object as the [[Prototype]] property of the myObj object created by the MyFunc constructor. Let's look at that in code.

function MyFunc() {};
var myObj = new MyFunc;
Object.getPrototypeOf(myObj) === MyFunc.prototype; // true

You might be wondering where the object assigned to prototype comes from. When we define a function, this object is instantiated and set as the value of the prototype property for that function.

This prototype object has a property, constructor, which points back to the function. Remember earlier we saw that when you create an object with a constructor, it has access to a property named constructor, which references the constructor which created the object? The reason the object can reference this property is that it delegates the call to its [[Prototype]] object, which is the prototype object of the constructor.

One more thing to look at here is that constructors also have a [[Prototype]] property. This makes sense because constructors are also objects, and as we said earlier all objects have a [[Prototype]] property. The [[Prototype]]property of a constructor (usually) never points to the same object as its prototype property. For custom constructors the [[Prototype]] property points to the object assigned to the prototype property of Function. Again this makes sense since Function is a constructor for functions.

Phew! All of this might have been quite a lot to take in, so before moving forward let’s recap on a couple of important points:

  • All objects have a [[Prototype]] property which points that object's 'prototype' object.
  • Constructors have a prototype property. This points to an object which is used as the value of the [[Prototype]]property for objects created by that constructor.

Constructing the chain

We can leverage the fact that an object’s [[Prototype]] property points to the same object as its constructor's prototype property, along with JavaScript's behaviour delegation, in order to share behaviour among objects of the same type.

Let’s go back to our animal example from earlier.

function Animal(name, age, species) {
this.name = name;
this.age = age;
this.species = species;
}
rex = new Animal('Rex', 4, 'dog');
paws = new Animal('Paws', 11, 'cat');
fluffy = new Animal('Fluffy', 2, 'rabbit');

In the code above, we’ve created our three animal objects using the Animal constructor, but currently the move method is not defined anywhere.

rex.move(); // TypeError: rex.move is not a function

If we want to define the the method in such a way that all our existing animal objects can access it, we can add it to [[Prototype]] object for those objects, which is the same object as Animal.prototype.

Object.getPrototypeOf(rex) === Animal.prototype; // true

By defining the method on this ‘prototype’ object, when our animal objects call this method that call is delegated up the prototype chain to the ‘prototype’ object where it is defined.

Animal.prototype.move = function() {
console.log(this.name + ' is walking.');
};
rex.move(); // 'Rex is walking.'
paws.move(); // 'Paws is walking.'
fluffy.move(); // 'Fluffy is walking.'

To be clear, unlike our earlier example where each object received a copy of the function, this method does not exist directly on the animal objects. Instead it exists on their ‘prototype’ object and is available to them through behaviour delegation.

We can verify this by using the hasOwnProperty() method. This is a method available to all objects via the prototypeobject of Object (which is on the prototype chain of all custom objects). This method is called on an object and takes a property name as an argument, it returns true if the property is actually defined on the object (as opposed to elsewhere on its prototype chain) and false otherwise.

rex.hasOwnProperty('move'); // false
Object.getPrototypeOf(rex).hasOwnProperty('move'); // true

The fact that the property is defined on the prototype and not the objects themselves, means that if we want to change the method we can update it in one place rather than having to do it on each object.

Animal.prototype.move = function() {
console.log(this.name + ' is running.');
};
rex.move(); // 'Rex is running.'
paws.move(); // 'Paws is running.'
fluffy.move(); // 'Fluffy is running.'

This provides us with an easy way to share behaviour between lots of different objects.


Object Creation Patterns

This approach of using a constructor to create objects and sharing behaviour between those objects by adding methods to a constructor’s prototype object is known as the 'pseudo-classical' object creation pattern. The examples we've looked at so far have been fairly simple, but it is possible to create much longer and more complex prototype chains using the pseudo-classical pattern. We'll look at an example of this shortly. As a counter-point to this, we'll see how the OLOO pattern creates a prototype chain without using constructors at all.

The Pseudo-classical Pattern

So far, in our basic examples of the pseudo-classical pattern, we’ve been adding behaviours to the existing prototypeobject of our constructors. To create longer prototype chains with this pattern, we actually need to replace the prototypeobject of constructors down the chain with an object created by a constructor further up the chain. That might be a bit difficult to picture, so let's build on our Animal example to see how it works.

Say we wanted more specific object types for our different animals, but we also wanted to delegate general animal behaviours to a basic animal prototype, we could do this by creating different animal constructors with an Animal object as the prototype object for those constructors.

function Animal(name, age, species) {
this.name = name;
this.age = age;
this.species = species;
}
function Dog(name, age, breed) {
Animal.call(this, name, age, 'dog');
this.breed = breed;
};
function Cat(name, age, colour) {
Animal.call(this, name, age, 'cat');
this.colour = colour;
};
Dog.prototype = new Animal;
Cat.prototype = new Animal;
rex = new Dog('Rex', 4, 'bulldog');
paws = new Cat('Paws', 11, 'tabby');

The use of call in Dog and Cat, executes Animal as a function (not as a constructor) but with the objects created by the Dog and Cat constructors as the execution context (this). This allows us to group 'general' attributes such as name and age in one place (Animal) and so avoid repetition in our Dog and Cat constructors. It is important to note that the properties are actually defined on the objects created by the Dog and Cat constructors.

rex.name; // 'Rex'
paws.name; // 'Paws'
rex.hasOwnProperty('name'); // true
paws.hasOwnProperty('name'); // true

Using this pattern, we can also define specific properties on the different types of animal. Dog objects have a breedproperty, and Cat objects have a colour property.

rex.breed; // 'bulldog'
paws.breed; // undefined
rex.colour; // undefined
paws.colour; // 'tabby'

As we mentioned earlier, we can also use this pattern to define general behaviours up the chain and more specific behaviours further down.

Animal.prototype.move = function() {
console.log(this.name + ' is walking.');
};
Dog.prototype.bark = function() {
console.log(this.name + ' says woof woof!');
};
Cat.prototype.purr = function() {
console.log(this.name + ' says purrrr....');
};

The move method is available to all objects down the chain from Animal.prototype, but bark is only available to those below Dog.prototype and purr to those below Cat.prototype.

rex.move(); // 'Rex is walking.'
paws.move(); // 'Paws is walking.'

rex.bark(); // 'Rex says woof woof!'
paws.bark(); // TypeError: paws.bark is not a function

rex.purr(); // TypeError: rex.purr is not a function
paws.purr(); // 'Paws says purrrr....'

The constructor property

Something to be aware of when using this approach is the effect on the constructor property.

We mentioned earlier that when we create an object with a constructor, it has access to a property named constructor, which references the constructor which created the object. We also said that this property exists on the object assigned to the prototype property of the constructor.

This object is instantiated when we define the function, and the value of constructor automatically set to the function.

When we replace the prototype object of constructor function, we no longer have a constructor property pointing back to the constructor.

If we reference constructor on our Dog object rex, we might expect this to point back to Dog, but it doesn't. It instead points to Animal

rex.constructor === Dog; // false
rex.constructor === Animal; // true

The reason for this is that we replaced the object assigned to Dog.prototype with the object returned by new Animal. This object doesn't have a constructor property, and neither does the object assigned to rex, so when we call rex.constructor this is delegated up the chain to the object which is the [[Prototype]] of Dog.prototype. Because of the reassignment of Dog.prototype, that object is now the Animal.prototype object, and so its constructor property points to Animal.

If maintaining the constructor relationship is important to our program, we can 'reset' this relationship by adding the property to the new Dog.prototype object.

Dog.prototype.constructor = Dog;
rex.constructor === Dog; // true

The pseudo-classical pattern and class-based inheritance

So far we’ve talked a lot about the mechanics of the pseudo-classical pattern, but not much about the mental model that using that pattern engenders.

The idea of defining constructors to create objects, and using the prototype objects of those constructors (almost as though they were an 'extension' of the constructor) in order to share behaviours, might lead us to imagine a hierarchical structure such as this:

If you think this looks a lot like the class-based inheritance of a language like Ruby or Java, you’d be right. The pseudo-classical object-creation pattern effectively mimics class-based inheritance without classes. The ES6 class syntax moves even further towards this paradigm.

class Animal {
constructor(name, age, species) {
this.name = name;
this.age = age;
this.species = species;
}
move() {
console.log(this.name + ' is walking.');
}
}
class Dog extends Animal {
constructor(name, age, breed) {
super(name, age, 'dog');
this.breed = breed;
}
bark() {
console.log(this.name + ' says woof woof!');
}
}
class Cat extends Animal {
constructor(name, age, colour) {
super(name, age, 'cat');
this.colour = colour;
}
purr() {
console.log(this.name + ' says purrrr....');
}
}
rex = new Dog('Rex', 4, 'bulldog');
paws = new Cat('Paws', 11, 'tabby');
rex.name; // 'Rex'
paws.name; // 'Paws'
rex.move(); // 'Rex is walking.'
paws.move(); // 'Paws is walking.'
rex.bark(); // 'Rex says woof woof!'
paws.bark(); // TypeError: paws.bark is not a function
rex.purr(); // TypeError: rex.purr is not a function
paws.purr(); // 'Paws says purrrr....'

The use of the class syntax together with extends does away with the need to manually set the prototype of the Catand Dog constructors to an Animal object. The super keyword replaces the use of the call method from our ES5 example.

Another advantage of class syntax is that, unlike the ES5 syntax, it maintains the object/ constructor relationship without having to manually reset the constructor property.

rex.constructor; // Dog
paws.constructor; // Cat

Something really important thing to understand about ES6 class syntax though is that it doesn't suddenly make JavaScript a class-based language with classical inheritance. Using class, extends, super and so on is just syntactical sugar on top of JavaScript's existing prototypal structure.

When we use the pseudo-classical pattern (whether that’s with ES5 or ES6 syntax), if we ignore the way the objects are created what we actually end up with is a bunch of objects linked to other objects via their [[Prototype]] property.

The OLOO Pattern

The OLOO pattern is an object creation pattern popularised by Kyle Simpson. Unlike the pseudo-classical pattern, OLOO doesn’t attempt to mimic a class-based hierarchy. Instead it leverages the fact that prototype chain is essentially just objects linked to other objects via their [[Prototype]] property in order to do away with the need for constructors altogether. In fact OLOO is simply an acronym for Objects Linked to Other Objects.

In JavaScript, the [[Prototype]] mechanism links objects to other objects. There are no abstract mechanisms like “classes”, no matter how much you try to convince yourself otherwise.
— Kyle Simpson

The OLOO pattern uses the Object.create() method to instantiate new objects. This method takes an object as an argument, and returns a new object whose [[Prototype]] property is set to the object that was passed into the method. Let's look at an example of that in code.

var myObj = {};
var myObj2 = Object.create(myObj);
Object.getPrototypeOf(myObj2) === myObj; // true

This effectively allows us to link one object to another object via JavaScript’s prototype chain without having to use a constructor.

Let’s see how our animal example would work with the OLOO pattern.

var Animal = {
initAnimal: function(name, age, species) {
this.name = name;
this.age = age;
this.species = species;
return this;
},
move: function() {
console.log(this.name + ' is walking.');
}
}
var Dog = Object.create(Animal);
Dog.initDog = function(name, age, breed) {
this.initAnimal(name, age, 'dog');
this.breed = breed;
return this;
};
Dog.bark = function() {
console.log(this.name + ' says woof woof!');
};
var Cat = Object.create(Animal);
Cat.initCat = function(name, age, colour) {
this.initAnimal(name, age, 'cat');
this.colour = colour;
return this;
};
Cat.purr = function() {
console.log(this.name + ' says purrrr....');
};
rex = Object.create(Dog).initDog('Rex', 4, 'bulldog');
paws = Object.create(Cat).initCat('Paws', 11, 'tabby');
rex.name; // 'Rex'
paws.name; // 'Paws'
rex.move(); // 'Rex is walking.'
paws.move(); // 'Paws is walking.'
rex.bark(); // 'Rex says woof woof!'
paws.bark(); // TypeError: paws.bark is not a function
rex.purr(); // TypeError: rex.purr is not a function
paws.purr(); // 'Paws says purrrr....'

If you’re more used to the pseudo-classical pattern this code might look a little unusual, so let’s break it down.

First we create an object using literal notation and assign it to a variable called Animal (as with the pseudo-classical pattern, the capitalisation is just a convention here, though our Animal object is not a constructor). The object has a couple of methods: initAnimal() and move(). The move() method is the same as the one from our pseudo-classical example. The initAnimal() method simply defines the name, age, and species properties on whatever object it is called on (this); it then returns that object.

We next create a couple more objects using Object.create() and assign them to Dog and Cat variables. Because we passed in our Animal object to Object.create(), this is set as the value of the [[Prototype]] property for the Dog and Cat objects.

Note that that Animal, Dog, and Cat are just normal objects and not constructors.

We then add a couple of methods to our Dog and Cat objects. initDog and initCat both initially call initAnimal on the object on which they are being called (this), and then define a further property (breed and colour respectively) on that same object; they then return the object (we'll see later why this explicit return is useful). The bark and purr methods are the same as from our pseudo-classical example.

We next create two more objects using Object.create() and assign them to the rex and paws variables. Because we passed in our Dog and Cat objects to Object.create(), these objects are set as the value of the [[Prototype]]property for the rex and paws objects respectively. We chain the initDog() and initCat() method calls onto our Object.create calls in order to define the various properties on our objects. There's a couple of things to note here:

  1. The initDog() and initCat() methods are able to call initAnimal() on the object instantiated by Object.create(i.e. this) because that object can delegate that method call to the Animal object which is set as the [[Prototype]]of those objects.
  2. The fact that the initDog() and initCat() methods return the object they are called on (this) means that we can chain them on Object.create and still have rex and paws assigned to the objects. If they didn't return this we would have to call them separately rather than chain them.

The most important thing to understand about this OLOO code example is that we end up with exactly the same objects, with the same relationships, as we did with the pseudo-classical approach. The difference is that we achieve that structure without having to use constructors and all the associated complexity that they bring.

We don’t have to deal with defining constructors and setting up their prototype objects, or worry about bugs caused by forgetting to use new, or making our constructors scope-safe. More importantly, dealing with just objects rather than constructors provides us with a much simpler mental model and frees us from the constraints of thinking of our object relationships in terms of a class hierarchy; it allows us to think about JavaScript prototype chain as it actually is, rather than abstracting it to an constrictive and non-existent structure.

Now we just set up objects linked to each other, without needing all the cruft and confusion of things that look (but don’t behave!) like classes, with constructors and prototypes and new calls. Ask yourself: if I can get the same functionality with OLOO style code as I do with “class” style code, but OLOO is simpler and has less things to think about, isn’t OLOO better?
— Kyle Simpson

Ultimately the approach you take, and the object creation pattern you use, will depend on a number of different factors, but using the OLOO pattern makes a lot of sense. The simplicity of its mental model and the flexibility it can bring to your code mean it is definitely worth considering, even with ES6 class syntax now available to us.

Even if you are going to use the OLOO pattern in your own projects, it’s also useful to know about constructors and understand how they work. They are still widely used and you will more than likely encounter the pseudo-classical pattern in code that you have to work with.


Summary

We’ve covered quite a lot of ground, so let’s sum up some of the key points of what we’ve discussed.

  • All objects have a [[Prototype]] property which points to another object. We can use this property to 'link' objects together to form a 'prototype chain'.
  • When we call a method on an object, JavaScript will first look in the object for a matching property and then search further up the prototype chain if necessary. We can therefore use the prototype chain to ‘share behaviour’ between objects.
  • Constructors are function objects which create objects. Constructors have a prototype property which points to an object. When we create an object with a constructor the prototype object of the constructor is set as the [[Prototype]] object of the newly created object.
  • Using constructors to create objects and the constructor prototype to share behaviour is an object creation pattern known as the pseudo-classical pattern.
  • The OLOO pattern can create the same objects and [[Prototype]] relationships in a simpler way without the use of constructors by using Object.create().

The title of this article is a small tribute to Aretha Franklin, who sadly passed away last week.