Illustration by

Prototypal Object-Oriented Programming using JavaScript

Douglas Crockford accurately described JavaScript as the world’s most misunderstood language. A lot of programmers tend to think of it as not a “proper” language because it lacks the common object-oriented programming concepts. I myself developed the same opinion after my first JavaScript project ended up a hodgepodge, as I couldn’t find a way to organize code into classes. But as we will see, JavaScript comes packed with a rich system of object-oriented programming that many programmers don’t know about.

Article Continues Below

Back in the time of the First Browser War, executives at Netscape hired a smart guy called Brendan Eich to put together a language that would run in the browser. Unlike class-based languages like C++ and Java, this language, which was at some point called LiveScript, was designed to implement a prototype-based inheritance model. Prototypal OOP, which is conceptually different from the class-based systems, had been invented just a few years before to solve some problems that class-based OOP presented and it fit very well with LiveScript’s dynamic nature.

Unfortunately, this new language had to “look like Java” for marketing reasons. Java was the cool new thing in the tech world and Netscape’s executives wanted to market their shiny new language as “Java’s little brother.” This seems to be why its name was changed to JavaScript. The prototype-based OOP system, however, didn’t look anything like Java’s classes. To make this prototype-based system look like a class-based system, JavaScript’s designers came up with the keyword new and a novel way to use constructor functions. The existence of this pattern and the ability to write “pseudo class-based” code has led to a lot of confusion among developers.

Understanding the rationale behind prototype-based programming was my “aha” moment with JavaScript and resolved most of the gripes I had with the language. I hope learning about prototype-based OOP brings you the same peace of mind it brought me. And I hope that exploring a technique that has not been fully explored excites you as much as it excites me.

Prototype-based OOP#section2

Conceptually, in class-based OOP, we first create a class to serve as a “blueprint” for objects, and then create objects based on this blueprint. To build more specific types of objects, we create “child” classes; i.e., we make some changes to the blueprint and use the resulting new blueprint to construct the more specific objects.

For a real-world analogy, if you were to build a chair, you would first create a blueprint on paper and then manufacture chairs based on this blueprint. The blueprint here is the class, and chairs are the objects. If you wanted to build a rocking chair, you would take the blueprint, make some modifications, and manufacture rocking chairs using the new blueprint.

Now take this example into the world of prototypes: you don’t create blueprints or classes here, you just create the object. You take some wood and hack together a chair. This chair, an actual object, can function fully as a chair and also serve as a prototype for future chairs. In the world of prototypes, you build a chair and simply create “clones” of it. If you want to build a rocking chair, all you have to do is pick a chair you’ve manufactured earlier, attach two rockers to it, and voilà! You have a rocking chair. You didn’t really need a blueprint for that. Now you can just use this rocking chair for yourself, or perhaps use it as a prototype to create more rocking chairs.

JavaScript and prototype-based OOP#section3

Following is an example that demonstrates this kind of OOP in JavaScript. We start by creating an animal object:

var genericAnimal = Object.create(null);

Object.create(null) creates a new empty object. (We will discuss Object.create() in further detail later.) Next, we add some properties and functions to our new object:

genericAnimal.name = 'Animal';
genericAnimal.gender = 'female';
genericAnimal.description = function() {
	return 'Gender: ' + this.gender + '; Name: ' + this.name;
};

genericAnimal is a proper object and can be used like one:

console.log(genericAnimal.description());
//Gender: female; Name: Animal

We can create other, more specific animals by using our sample object as a prototype. Think of this as cloning the object, just like we took a chair and created a clone in the real world.

var cat = Object.create(genericAnimal);

We just created a cat as a clone of the generic animal. We can add properties and functions to this:

cat.purr = function() {
	return 'Purrrr!';
};

We can use our cat as a prototype and create a few more cats:

var colonel = Object.create(cat);
colonel.name = 'Colonel Meow';

var puff = Object.create(cat);
puff.name = 'Puffy';

You can also observe that properties/methods from parents were properly carried over:

console.log(puff.description());
//Gender: female; Name: Puffy

The new keyword and the constructor function#section4

JavaScript has the concept of a new keyword used in conjunction with constructor functions. This feature was built into JavaScript to make it look familiar to people trained in class-based programming. You may have seen JavaScript OOP code that looks like this:

function Person(name) {
	this.name = name;
	this.sayName = function() {
		return "Hi, I'm " + this.name;
	};
}
var adam = new Person('Adam');

Implementing inheritance using JavaScript’s default method looks more complicated. We define Ninja as a sub-class of Person. Ninjas can have a name as they are a person, and they can also have a primary weapon, such as shuriken.

function Ninja(name, weapon) {
  Person.call(this, name);
  this.weapon = weapon;
}
Ninja.prototype = Object.create(Person.prototype);
Ninja.prototype.constructor = Ninja;

While the constructor pattern might look more attractive to an eye that’s familiar with class-based OOP, it is considered problematic by many. What’s happening behind the scenes is prototypal OOP, and the constructor function obfuscates the language’s natural implementation of OOP. This just looks like an odd way of doing class-based OOP without real classes, and leaves the programmer wondering why they didn’t implement proper class-based OOP.

Since it’s not really a class, it’s important to understand what a call to a constructor does. It first creates an empty object, then sets the prototype of this object to the prototype property of the constructor, then calls the constructor function with this pointing to the newly-created object, and finally returns the object. It’s an indirect way of doing prototype-based OOP that looks like class-based OOP.

The problem with JavaScript’s constructor pattern is succinctly summed up by Douglas Crockford:

JavaScript’s constructor pattern did not appeal to the classical crowd. It also obscured JavaScript’s true prototypal nature. As a result, there are very few programmers who know how to use the language effectively.

The most effective way to work with OOP in JavaScript is to understand prototypal OOP, whether the constructor pattern is used or not.

Understanding delegation and the implementation of prototypes#section5

So far, we’ve seen how prototypal OOP differs from traditional OOP in that there are no classes—only objects that can inherit from other objects.

Every object in JavaScript holds a reference to its parent (prototype) object. When an object is created through Object.create, the passed object—meant to be the prototype for the new object—is set as the new object’s prototype. For the purpose of understanding, let’s assume that this reference is called __proto__1. Some examples from the previous code can illustrate this point:

The line below creates a new empty object with __proto__ as null.

var genericAnimal = Object.create(null); 

The code below then creates a new empty object with __proto__ set to the genericAnimal object, i.e. rodent.__proto__ points to genericAnimal.

var rodent = Object.create(genericAnimal);
 rodent.size = 'S';

The following line will create an empty object with __proto__ pointing to rodent.

var capybara = Object.create(rodent);
//capybara.__proto__ points to rodent
//capybara.__proto__.__proto__ points to genericAnimal
//capybara.__proto__.__proto__.__proto__ is null

As we can see, every object holds a reference to its prototype. Looking at Object.create without knowing what exactly it does, it might look like the function actually “clones” from the parent object, and that properties of the parent are copied over to the child, but this is not true. When capybara is created from rodent, capybara is an empty object with only a reference to rodent.

But then—if we were to call capybara.size right after creation, we would get S, which was the size we had set in the parent object. What blood-magic is that? capybara doesn’t have a size property yet. But still, when we write capybara.size, we somehow manage to see the prototype’s size property.

The answer is in JavaScript’s method of implementing inheritance: delegation. When we call capybara.size, JavaScript first looks for that property in the capybara object. If not found, it looks for the property in capybara.__proto__. If it didn’t find it in capybara.__proto__, it would look in capybara.__proto__.__proto__. This is known as the prototype chain.

If we called capybara.description(), the JavaScript engine would start searching up the prototype chain for the description function and finally discover it in capybara.__proto__.__proto__ as it was defined in genericAnimal. The function would then be called with this pointing to capybara.

Setting a property is a little different. When we set capybara.size = 'XXL', a new property called size is created in the capybara object. Next time we try to access capybara.size, we find it directly in the object, set to 'XXL'.

Since the prototype property is a reference, changing the prototype object’s properties at runtime will affect all objects using the prototype. For example, if we rewrote the description function or added a new function in genericAnimal after creating rodent and capybara, they would be immediately available for use in rodent and capybara, thanks to delegation.

Creating Object.create#section6

When JavaScript was developed, its default way of creating objects was the keyword new. Then many notable JavaScript developers campaigned for Object.create, and eventually it was included in the standard. However, some browsers don’t support Object.create (you know the one I mean). For that reason, Douglas Crockford recommends including the following code in your JavaScript applications to ensure that Object.create is created if it is not there:

if (typeof Object.create !== 'function') {
	Object.create = function (o) {
		function F() {}
		F.prototype = o;
		return new F();
	};
}

Object.create in action#section7

If you wanted to extend JavaScript’s Math object, how would you do it? Suppose that we would like to redefine the random function without modifying the original Math object, as other scripts might be using it. JavaScript’s flexibility provides many options. But I find using Object.create a breeze:

var myMath = Object.create(Math);

Couldn’t possibly get any simpler than that. You could, if you prefer, write a new constructor, set its prototype to a clone of Math, augment the prototype with the functions you like, and then construct the actual object. But why go through all that pain to make it look like a class, when prototypes are so simple?

We can now redefine the random function in our myMath object. In this case, I wrote a function that returns random whole numbers within a range if the user specifies one. Otherwise, it just calls the parent’s random function.

myMath.random = function() {
	var uber = Object.getPrototypeOf(this);
if (typeof(arguments[0]) === 'number' && typeof(arguments[1]) === 'number' && arguments[0] < arguments[1]) {
		var rand = uber.random();
		var min = Math.floor(arguments[0]);
		var max = Math.ceil(arguments[1]);
		return this.round(rand * (max - min)) + min;
	}
	return uber.random();
};

There! Now myMath.random(-5,5) gets you a random whole number between −5 and 5, while myMath.random() gets the usual. And since myMath has Math as its prototype, it has all the functionality of the Math object built into it.

Class-based OOP vs. prototype-based OOP#section8

Prototype-based OOP and class-based OOP are both great ways of doing OOP; both approaches have pros and cons. Both have been researched and debated in the academic world since before I was born. Is one better than the other? There is no consensus on that. But the key points everyone can agree on are that prototypal OOP is simpler to understand, more flexible, and more dynamic.

To get a glimpse of its dynamic nature, take the following example: you write code that extensively uses the indexOf function in arrays. After writing it all down and testing in a good browser, you grudgingly test it out in Internet Explorer 8. As expected, you face problems. This time it’s because indexOf is not defined in IE8.

So what do you do? In the class-based world, you could solve this by defining the function, perhaps in another “helper” class which takes an array or List or ArrayList or whatever as input, and replacing all the calls in your code. Or perhaps you could sub-class the List or ArrayList and define the function in the sub-class, and use your new sub-class instead of the ArrayList.

But JavaScript and prototype-based OOP’s dynamic nature makes it simple. Every array is an object and points to a parent prototype object. If we can define the function in the prototype, then our code will work as is without any modification!

if (!Array.prototype.indexOf) {
	Array.prototype.indexOf = function(elem) {
		//Your magical fix code goes here.
};
}

You can do many cool things once you ditch classes and objects for JavaScript’s prototypes and dynamic objects. You can extend existing prototypes to add new functionality—extending prototypes like we did above is how the well known and aptly named library Prototype.js adds its magic to JavaScript’s built-in objects. You can create all sorts of interesting inheritance schemes, such as one that inherits selectively from multiple objects. Its dynamic nature means you don’t even run into the problems with inheritance that the Gang of Four book famously warns about. (In fact, solving these problems with inheritance was what prompted researchers to invent prototype-based OOP—but all that is beyond our scope for this article.)

Class-based OOP emulation can go wrong#section9

Consider the following very simple example written with pseudo-classes:

function Animal(){
    this.offspring=[];
}

Animal.prototype.makeBaby = function(){ 
    var baby = new Animal();
    this.offspring.push(baby);
    return baby;
};

//create Cat as a sub-class of Animal
function Cat() {
}

//Inherit from Animal
Cat.prototype = new Animal();

var puff = new Cat();
puff.makeBaby();
var colonel = new Cat();
colonel.makeBaby();

The example looks innocent enough. This is an inheritance pattern that you will see in many places all over the internet. However, something funny is going on here—if you check colonel.offspring and puff.offspring, you will notice that each of them contains the same two babies! That’s probably not what you intended—unless you are coding a quantum physics thought experiment.

JavaScript tried to make our lives easier by making it look like we have good old class-based OOP going on. But it turns out it’s not that simple. Simulating class-based OOP without completely understanding prototype-based OOP can lead to unexpected results. To understand why this problem occurred, you must understand prototypes and how constructors are just one way to build objects from other objects.

What happened in the above code is very clear if you think in terms of prototypes. The variable offspring is created when the Animal constructor is called—and it is created in the Cat.prototype object. All individual objects created with the Cat constructor use Cat.prototype as their prototype, and Cat.prototype is where offspring resides. When we call makeBaby, the JavaScript engine searches for the offspring property in the Cat object and fails to find it. It then finds the property in Cat.prototype—and adds the new baby in the shared object that both individual Cat objects inherit from.

So now that we understand what the problem is, thanks to our knowledge of the prototype-based system, how do we solve it? The solution is that the offspring property needs to be created in the object itself rather than somewhere in the prototype chain. There are many ways to solve it. One way is that makeBaby ensures that the object on which the function is called has its own offspring property:

Animal.prototype.makeBaby=function(){
	var baby=new Animal(); 
	if(!this.hasOwnProperty('offspring')){
		this.offspring=[]; }
	this.offspring.push(baby); 
	return baby;
};

Backbone.js runs into a similar trap. In Backbone.js, you build views by extending the base Backbone.View “class.” You then instantiate views using the constructor pattern. This model is very good at emulating class-based OOP in JavaScript:

//Create a HideableView "sub-class" of Backbone.View
var HideableView = Backbone.View.extend({
    el: '#hideable', //the view will bind to this selector
    events : {
        'click .hide': 'hide'
    },
    //this function was referenced in the click handler above
    hide: function() {
      //hide the entire view
    	$(this.el).hide();
    }
});

var hideable = new HideableView();

This looks like simple class-based OOP. We inherited from the base Backbone.View class to create a HideableView child class. Next, we created an object of type HideableView.

Since this looks like simple class-based OOP, we can use this functionality to conveniently build inheritance hierarchies, as shown in the following example:

var HideableTableView = HideableView.extend({
    //Some view that is hideable and rendered as a table.
});

var HideableExpandableView = HideableView.extend({
    initialize: function() {
        //add an expand click handler. We didn’t create a separate
        //events object because we need to add to the
        //inherited events.
        this.events['click .expand'] = 'expand';
    },
    expand: function () {
    	//handle expand
    }
});

var table = new HideableTableView();
var expandable = new HideableExpandableView();

This all looks good while you’re thinking in class-based OOP. But if you try table.events['click .expand'] in the console, you will see "expand"! Somehow, HideableTableView has an expand click handler, even though it was never defined in this class.

You can see the problem in action here: http://codepen.io/anon/pen/qbYJeZ

The problem above occurred because of the same reason outlined in the earlier example. In Backbone.js, you need to work against the indirection created by trying to make it look like classes, to see the prototype chain hidden in the background. Once you comprehend how the prototype chain would be structured, you will be able to find a simple fix for the problem.

In conclusion#section10

Despite prototypal OOP underpinning one of the most popular languages out there today, programmers are largely unfamiliar with what exactly prototype-based OOP is. JavaScript itself may be partly to blame because of its attempts to masquerade as a class-based language.

This needs to change. To work effectively with JavaScript, developers need to understand the how and why of prototype-based programming—and there’s much more to it than this article. Beyond mastering JavaScript, in learning about prototype-based programming you can also learn a lot of things about class-based programming as you get to compare and contrast the two different methods.

Further Reading#section11

Douglas Crockford’s note on protoypal programming was written before Object.create was added to the standard.

An article on IBM’s developerWorks reinforces the same point on prototypal OOP. This article was the prototypal “aha” moment for me.

The following three texts will be interesting reads if you’re willing to dive into the academic roots of prototype-based programming:

Henry Lieberman of MIT Media Labs compares class-based inheritance with prototype-based delegation and argues that prototype-based delegation is the more flexible of the two concepts.

Classes versus Prototypes in Object-Oriented Languages is a proposal to use prototypes instead of classes by the University of Washington’s Alan Borning.

Lieberman’s and Borning’s work in the 1980s appears to have influenced the work that David Ungar and Randall Smith did to create the first prototype-based programming language: Self. Self went on to become the basis for the prototype-based system in JavaScript. This paper describes their language and how it omits classes in favor of prototypes.

Notes

  • 1. The __proto__ property is used by some browsers to expose an object’s prototype, but it is not standard and is considered obsolete. Use Object.getPrototypeOf() as a standards-compliant way of obtaining an object’s prototype in modern browsers.

About the Author

Mehdi Maujood

Mehdi Maujood is a software engineer working for The Resource Group in Pakistan, where he helps write software for various clients. His turbulent relationship with JavaScript has matured and stabilized over time. If not sighted in his natural habitat, he can be found in remote mountainous regions of the Himalayas and the Karakoram.

20 Reader Comments

  1. Well this is one way to look at OOP but it is based on a fallacious premise. JavaScript is not an OOP language and without major overhaul it will never be one. So please try not to use the OOP paradigm since it is very confusing to newbies and professionals alike. The less we use improper terminology the better it will be. JavaScript has some great features which are being obscured by all this messing around with trying to make it look like OOP.

  2. “Both have been researched and debated in the academic world since before I was born. Is one better than the other? There is no consensus on that.”

    There is no consensus??? It’s obvious that there is. The entire IT industry has spoken! It has roundly ignored prototypes, and for good reason. No other notable language created in the past quarter century has adopted object prototypes, except for 23-year-old Lua. The industry has shown a clear preference for class-based OOP, because while classes do have their problems, there is (currently) no better way to organize large-scale application code (say, in the hundreds of thousands of lines). Object prototypes would fall flat on its face here.

    Languages like Smalltalk and C++ are capable of writing programs as big as a million lines of code. JavaScript would be hopeless in these situations. Apparently, ECMA recognized this and tried to accommodate the popularity of classes.

    However, the latest ES6 class feature is only a half-assed implementation of class-based OOP. It’s just syntactic sugar over object prototypes. It still doesn’t support private state (member variables) in the way we expect. Member variables must be “faked” through a variety of workarounds such as programming convention, capturing normal variables with closures, and employing WeakMaps. ES6 is not a proper class-based OOP language like Smalltalk, C++, Java and Python.

    Let’s remember why JavaScript was created. Brendan Eich wanted a light, breezy, scripting language for the web browser that was flexible and forgiving. It was never intended for serious software engineering. The qualities that make it flexible (e.g, object prototypes and loose typing) are the same qualities that work against good engineering. For all of ECMA TC39’s efforts, this has not changed.

    Like I said, the IT industry has spoken. Nobody really wants object prototypes.

    JavaScript is not a misunderstood language. We know exactly what it is. JavaScript is a sloppy and undisciplined language wholly unsuitable for proper software engineering, esp. at scale.

  3. horrido, perhaps that is true. Modern languages are all class-based, although I’m not sure if it’s just because of its superiority or because the language that popularized OOP was class-based. That’s a different debate.

    But I would say it’s still immensely important to understand how prototypes work to be able to work effectively with JavaScript. Like you said, even the classes in es6 are built off prototypes.

  4. I’m not entirely convinced Javascript has serious purpose when it comes to software engineering. There are far more suitable languages that should be used. Not to say Javascript shouldn’t be used though. I guess it depends on the requirements of each individual case.

  5. Fairly novice here, but what’s with Snippet #12? Why would you use the arguments object when the function needs fixed arguments? Why do you use the Math object within when ‘uber’ is the Math object?

    Kind of threw me off the tutorial.

  6. Excellent article. Clearly understandable. I have some confusion with oop concept in javascript. but after reading this, I clearly understood. Thanks for sharing this article.

  7. Stopdoor, the function uses the arguments array because we want the user to be able to call both versions: myMath.random() for the default functionality and myMath.random(-5,5) for the functionality we coded. Math and uber are exactly the same thing. I just used uber to demonstrate how we can call methods on an object’s prototype. I think I should have exclusively used uber here.

  8. I find the opening metaphor of prototype based vs classical oop inheritance very useful, thanks for the wrap up.

  9. I think the biggest issue here is an understanding of how JS treats complex types (objects,arrays) vs simple types (string,number,bool). Most people expect a copy of every attribute when they create an object using ‘new’ however JS will only make copies of the simple data types and instead creates a pointer to the complex data types. If you included a property of this.name in Animal type, the two new Cats (puff and colonel) would have unique properties. However since the Array of offspring is just a pointer to the original, when you makeBaby is still is pointing to the original Animal.offspring. The same applies for passing values into a function. Pass an object as a parameter and any changes you make in that function to the object point to the original.

  10. It bugged me that you used gender, maybe use Kingdom instead, Animalia would be good…

    genericAnimal.kingdom = ‘Animalia’;

  11. An excellent article. Thank you for such a simple and informative explanation. This article actually made me wonder what it would be like to develop in JavaScript in “pure” prototype based OOP rather than using any type of class based system (including the imitation of class based OOP discussed in the article). So, I created a tiny library that removes any imitation of class based OOP from creating objects. It could also prove to be a useful learning tool when trying to understand/implement prototypal OOP without trying to wrap one’s mind around the class based imitation found in native JavaScript.

    I hope that it’s useful to someone, enjoy: https://www.npmjs.com/package/proto-proper

  12. information about javascript code that is very helpful for me who is studying deeper .. keep working , thanks to quality article , if you need information about more try visiting..Sepatu Running Adidas

  13. Just out of curiousity, is this the right solution to the backbone.js problem? (add the following code before the new expand handler statement)

    if(!this.hasOwnProperty('events')) {
    this.events = Object.create(Object.getPrototypeOf(this).events)
    }

  14. Very good article and thank you for taking the time to write it. I do have some differing opinions on whether or not the industry has decided on which version of OOP is best, but that is for another article.

  15. Since the prototype property is a reference, changing the prototype object’s properties at runtime will affect all objects using the prototype.

    Can you please explain this point?

    Only way I am able to modify the parent’s property is via child object’s _proto_ property. Still parent objects are without new property.

    Thanks a lot. Sorry for foolish question

Got something to say?

We have turned off comments, but you can see what folks had to say before we did so.

More from ALA

I am a creative.

A List Apart founder and web design OG Zeldman ponders the moments of inspiration, the hours of plodding, and the ultimate mystery at the heart of a creative career.
Career