Part 1: The JavaScript OLOO Pattern Explained (with pictures)

Having listened to a number of students during my software development studies, I observed a lot of confusion surrounding JavaScript’s Object Creation Patterns. For beginners it can be especially tricky — and without careful study, can lead to hesitation around using objects. With this in mind, I braced myself for a deep dive into learning JavaScript’s Object Creation patterns for the first time.

To my relief, my progress was smooth as I learned these patterns at Launch School — with little to no confusion. How was this done? Well, I am very happy to share my findings here in two parts:

  • Part 1 covers Prototype Inheritance and delegation in JavaScript with the OLOO pattern
  • Part 2 deals with the Pseudo-classical pattern — a combination of constructor functions and prototypes that create objects in JavaScript

As there is a plethora of technical information out there on JavaScript Objects, we will attempt to keep technicalities light. We will instead take a top-down, integrated approach to these articles. Before I get stuck into JavaScript prototypes, let us first discuss how other OOP languages create objects using classes.

Traditional Class-Based Objects

We will be expanding on Software Engineer Mehdi Maujood’s brilliant chair object metaphor:

In a class-based language, such as Ruby: classes are like blueprints. If we wanted to manufacture a chair for example, that has a width and height, we would create a class that serves as the “blueprint” and create (or instantiate) a chair based on that blueprint:

class Chair
def initialize(width, height)
@width = width
@height = height
end
end
my_chair = Chair.new(50, 45)

What if we then wanted to create a more specific object, say a desk chair? We must make changes to the blueprint. Desk chairs are typically more complex than a basic chair — their height can be adjusted and they have wheels. To accommodate both chair objects, we must keep our original Chair class (superclass) and create a more specific class DeskChair (subclass), which will set the original properties of our Chair class using the super keyword:

class Chair
def initialize(width, min_height)
@width = width
@min_height = min_height
end
end
class DeskChair < Chair
def initialize(width, min_height, max_height, wheels)
super(width, min_height)
@max_height = max_height
@wheels = wheels
end
end
my_chair = Chair.new(50, 45)
my_desk_chair = DeskChair.new(50, 45, 52, 5)

JavaScript Prototypes

Continuing with Mehdi Maujood’s chair metaphor — when it comes to prototypes, we don’t create blueprints or classes, we just create a chair object. Imagine chopping up some wood and building a chair out of it. This is a fully functional chair object and can work as the prototype for future chair objects:

let myChair = {
width: 50,
height: 45,
};
In JavaScript objects don’t need classes

Maujood goes on to explain: “In the world of prototypes, you build a chair and simply make ‘duplicates’ of it”. If we want to build our desk chair, we ‘duplicate’ our original chair using Object.create, give our new chair some adjustable height, add some wheels to it and ta-da! We have a desk chair! We didn’t have to create a blueprint for that now did we?

let myChair = {
width: 50,
minHeight: 45,
};
let myDeskChair = Object.create(myChair);
myDeskChair.maxHeight = 52;
myDeskChair.wheels = 5;

And if we wanted a chair object of any width and height we can simply add an init method to set initial values for a chair of any dimension:

let myChair = {
init(width, height) {
this.width = width;
this.height = height;
return this;
}
};
let anotherChair = Object.create(myChair).init(40,60);

There is a major yet subtle difference between class-based objects and prototypal objects. If we were to compare a Ruby desk chair object to a JavaScript desk chair object, aside from Ruby’s superficial Object id information: #<DeskChair: 0x000055e0cfa1fddc8, we would find an important distinction. Can you spot it in the code below?

Ruby’s Desk Chair:

p my_desk_chair#<DeskChair:0x000055e0cfa1fdc8 
@width=50, @min_height=45, @max_height=52, @wheels=5>

JavaScript‘s Desk Chair:

console.log(myDeskChair);{ maxHeight: 52, wheels: 5 }

To spot the difference here, we first need to understand JavaScript’s Prototypal Chain.

The Prototypal Chain: Inheritance & Delegation

If you looked close enough you might have noticed that the Ruby desk chair contained all its properties: width, min_height, max_height and wheels whereas our new JavaScript desk chair object only contains maxHeight and wheels. That’s strange…didn’t we ‘duplicate’ our original chair? Shouldn’t it have all the properties from our original chair prototype?

Actually….our new desk chair object does have access to all its properties:

console.log(myDeskChair);    // { maxHeight: 52, wheels: 5 }myDeskChair.width;           // 50
myDeskChair.min_height; // 45

Wait…what’s going on?! Those properties don’t exist on myDeskChair yet we still retain access to them — how is this possible?

As it turns out, myDeskChair starts out as a blank object that we added the maxHeight and wheels properties to. Every object in JavaScript contains a hidden property called [[Prototype]]. This property contains access to an object’s prototype. When we created our desk chair, Object.create sets myDeskChair's hidden [[Prototype]] property to reference the myChair object as its value.

To find the “missing” properties on myDeskChair, we can access any properties on our object’s prototype using JavaScript’s prototype chain.

When we attempt to access the width property from myDeskChair, JavaScript will check the myDeskChair object first. The width property is not found so JavaScript will lookup its prototype chain via myDeskChair‘s hidden [[Prototype]] property. It’s prototype is myChair – which JavaScript will search next and find that a width property exists. It will access and return the first width property it sees – enabling prototype properties further up the lookup chain that have the same name to be overridden.

At the top of the prototype chain lies the most basic prototype object called Object.prototype. All objects will have this object as their prototype by default. Object.prototype does not have a prototype of its own and will return null if we attempt to access its prototype:

This approach is known as prototypal inheritance or delegation. This is where newly created objects can delegate messages up its prototype chain to one of its prototypes, in order to retrieve the requested property or method. This keeps future objects small and efficient, containing only the necessary properties it needs that make it unique from other linked objects.

Conclusion

This Object creation pattern is known as OLOO or “Objects Linking to Other Objects”, which is at the heart of how objects really work in JavaScript. Historically speaking OLOO was introduced after the Pseudo-classical pattern, in an attempt to return to the true nature of JavaScript objects, prototypes and delegation.

The Pseudo-classical Object creation pattern however was the original way of creating objects in JavaScript and is a valid pattern in its own right. In Part 2, we will discuss the breakdown of how it works and how objects are secretly working behind the scenes!

Continue to Part 2 of our discussion on JS OOP Patterns…

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store