The Secret Life of JavaScript Objects: a Tale of Prototypes

Entire books have been written on JavaScript objects and the prototype system. Yet beginners and even experienced developers struggle to learn and remember what the stuff is about. Here’s a refresher for you!

The secret life of JavaScript objects

This post is an extract from “The Little JavaScript Book”. Claim a free PDF/ePub/Mobi of the early release or get your copy on Leanpub.

Prelude: JavaScript fundamentals

JavaScript builds on seven lego bricks called “types” of the language. The complete list is:

  • String
  • Number
  • Boolean
  • Object
  • Symbol
  • Null
  • Undefined

These types are also called “primitives”, except Object which is considered a type on its own. Object in JavaScript is the backbone of the language. JavaScript objects are containers for keys and values. Think of an object as a phone book:

var obj = {
  alex: "333335685454",
  valentino: "554234242",
  tom: "323f43422"
};

Every key in an object is accessible with the dot notation:

obj.alex;

or with the bracket notation:

obj["alex"];

If your familiar with other programming languages, JavaScript objects have parallel with Python dictionaries and Ruby hash tables, to name two. JavaScript objects can also contain functions. Consider the following example, a person with a name and a function for printing person.name:

var person = {
  name: "alex",
  printName: function() {
    console.log(person.name);
  }
};

person.printName();

When a function gets called as part of a JavaScript object, the JavaScript engine is able to infer the “context” in which the function is running. So in our example instead of printing person.name we can simply refer to the person object as “this”:

var person = {
  name: "alex",
  printName: function() {
    console.log(this.name);
  }
};

person.printName();

Here “this” is the person object. “this” is a powerful concept and you’ll find it everywhere in JavaScript. But for now don’t worry too much about it. Let’s focus our attention on JavaScript objects.

As I said they’re containers for other stuff and the most important building block of the language. So important that it’s said everything is an object in JavaScript. But what that means exactly?

Everything is an object!

How many times have you heard “everything is an object in JavaScript“? Have you ever asked yourself what’s the true meaning of that? “Everything is an object” is common to other languages too, like Python.

But objects in Python are not just containers for values like a JavaScript object. Object in Python is a class.

There is something similar in JavaScript but an “object” in JS is just a container for keys and values:

var obj = { name: "Tom", age: 34 }

Really, an object in JavaScript is a “dumb” type yet a lot of other entities seem to derive from objects. Even arrays. Create an array in JavaScript like so:

var arr = [1,2,3,4,5]

and then check it out with the typeof operator. You’ll see a surprising result:

typeof arr
"object"

It appears that arrays are a special kind of object! Even functions in JavaScript are objects. And there’s more if you dig deeper. Create a function and you will have methods ready for use, attached to that function:

var a = function(){ return false; }
a.toString()

Output:

"function(){ return false; }"

There must be something more under the hood because I didn’t attach toString to my function. Did you? Where does it come from? Turns out Object too has a method named toString. Seems like our function has the same methods of Object!

Object.toString()

The mystery thickens even more if we look at all the methods and properties “attached” to a simple JavaScript function:

Even a simple JavaScript function carries a lot of methods
Even a simple JavaScript function carries a lot of “default” methods

Who put those methods there? I said that functions in JavaScript are a special kind of object. Could it be an hint?

Maybe! But for now let’s hold our joy. Take a look again at the picture above: there is a strangely named property on our function called prototype. What’s that?

What is prototype in JavaScript?

prototype in JavaScript is an object. It is like a backpack, attached to most of the JavaScript built-in objects. For example Object, Function, Array, Date, Error, all have a “prototype”:

typeof Object.prototype // 'object'
typeof Date.prototype // 'object'
typeof String.prototype // 'object'
typeof Number.prototype // 'object'
typeof Array.prototype // 'object'
typeof Error.prototype // 'object'

Pay attention that built-in objects have a capital letter and resemble those lego bricks we saw earlier:

  • String
  • Number
  • Boolean
  • Object
  • Symbol
  • Null
  • Undefined

These lego bricks are JavaScript’s types, and most of them are also primitives, except Object which is a type. Built-in objects on the other hand are like mirrors of JavaScript’s types and are used as a function too. For example you can use String as a function for converting a number to a string:

String(34)

But for now let’s stick to “prototype”.

Prototype is an home for all the common method and properties that should be available across “child” objects deriving from an ancestor. That is, given an original prototype, JavaScript developers can create new objects that will use a single prototype as the source of truth for common functions.

Let’s see how (spoiler: Object.create).

The secret life of JavaScript objects: a new person

Suppose you’re absolutely new to the language but your boss gives you a task with JavaScript.

You should build a chat application and she said that Person is one of the “models” of this app. A person can connect to a channel, can send messages and maybe is welcomed with a nice greeting when she logs in.

Being new to JavaScript you don’t even know where to start. But you’re smart and from the documentation you’ve been reading lately it appears that JavaScript objects are really powerful. In particular this page on MDN lists all the methods available on JavaScript objects and create() looks interesting.

Object.create() “creates a new object with the specified prototype object…“.

Maybe there is a way to create a “primitive” Person from which other objects can borrow methods and properties? Objects in JavaScript may contain not only simple values but also functions:

var firstObj = {
  name: "Alex",
  age: 33,
  hello: function() {
    console.log("Hello " + this.name);
  }
};

Now that’s a game changer! Let’s create a Person object then. While we’re there let’s use ES6 template literals for concatenating “Hello” with the name:

var Person = {
  name: "",
  age: 0,
  greet: function() {
    console.log(`Hello ${this.name}`);
  }
};

You may wonder why I’m using a capital letter for Person. We’ll see later in detail but for now think of it as of a convention developers use for signalling “models”. Person is a model in your application.

Given this Person blueprint we need to create more people starting from that single Person. And Object.create() is your friend here.

Creating and linking JavaScript objects

Objects in JavaScript are somehow linked together. Object.create() creates new objects starting from an original object. Let’s create a new person then:

var Person = {
  name: "noname",
  age: 0,
  greet: function() {
    console.log(`Hello ${this.name}`);
  }
};

var Tom = Object.create(Person);

Now, Tom is a new person but I didnt’t specify any new method or property on it. Yet it still has access to the original name and age:

var Person = {
  name: "noname",
  age: 0,
  greet: function() {
    console.log(`Hello ${this.name}`);
  }
};

var Tom = Object.create(Person);

var tomAge = Tom.age;
var tomName = Tom.name;

console.log(`${tomAge} ${tomName}`);

// Output: 0 noname

Bingo! Now you can create new people starting from a single, common ancestor. But the weird thing is that new objects remains connected to the original object. Not a big problem since “children” objects can customize properties and methods:

var Person = {
  name: "noname",
  age: 0,
  greet: function() {
    console.log(`Hello ${this.name}`);
  }
};

var Tom = Object.create(Person);

Tom.age = 34;
Tom.name = "Tom";
var tomAge = Tom.age;
var tomName = Tom.name;

console.log(`${tomAge} ${tomName}`);

// Output: 34 Tom

And that’s called “shadowing” the original properties. There is also another way for passing properties to our new object. Object.create takes another object as the second argument where you can specify keys and values for the new object:

var Tom = Object.create(Person, {
  age: {
    value: 34
  },
  name: {
    value: "Tom"
  }
});

Properties configured this way are by default not writable, not enumerable, not configurable. Not writable means you cannot change that property later, the alteration is simply ignored:

var Tom = Object.create(Person, {
  age: {
    value: 34
  },
  name: {
    value: "Tom"
  }
});

Tom.age = 80;
Tom.name = "evilchange";

var tomAge = Tom.age;
var tomName = Tom.name;

Tom.greet();

console.log(`${tomAge} ${tomName}`);

// Hello Tom
// 34 Tom

Not enumerable means that properties will not show in a for…in loop for for example:

for (const key in Tom) {
  console.log(key);
}

// Output: greet

But as you can see, linked properties shows up because the JavaScript engine goes up the link chain and finds greet up on the “parent” object. Finally not configurable means the property neither can be modified, nor deleted:

Tom.age = 80;
Tom.name = "evilchange";
delete Tom.name;
var tomAge = Tom.age;
var tomName = Tom.name;

console.log(`${tomAge} ${tomName}`);

// 34 Tom

If you want to change the behaviour of properties just specify whether you want them writable, configurable and maybe enumerable:

var Tom = Object.create(Person, {
  age: {
    value: 34,
    enumerable: true,
    writable: true,
    configurable: true
  },
  name: {
    value: "Tom",
    enumerable: true,
    writable: true,
    configurable: true
  }
});

Now, back to our person. Tom has also access to greet():

var Person = {
  name: "noname",
  age: 0,
  greet: function() {
    console.log(`Hello ${this.name}`);
  }
};

var Tom = Object.create(Person);

Tom.age = 34;
Tom.name = "Tom";
var tomAge = Tom.age;
var tomName = Tom.name;
Tom.greet();

console.log(`${tomAge} ${tomName}`);

// Hello Tom
// 34 Tom

Don’t worry too much about “this” for now. You’ll learn more about it. For now keep in mind that “this” is a reference to some object in which the function is executing. In our case greet() runs in the context of Tom and for that reason has access to “this.name”.

And now that you know a bit more about JavaScript objects let’s explore another pattern for creating entities: the constructor function.

Constructing JavaScript objects

Up until now I gave you just an hint of the “prototype” but other than playing with Object.create() we didnt’ use it directly.

A lot of developers coming from more traditional languages like Java stumbled upon Object.create() and “prototypal” over the years. They had to find a way for making sense of this weird JavaScript language. So with the time a new pattern emerged: the constructor function.

Using a function for creating new objects sounded reasonable. Suppose you want to transform your Person object to a function, you could come up with the following code:

function Person(name, age) {
  var newPerson = {};
  newPerson.age = age;
  newPerson.name = name;
  newPerson.greet = function() {
    console.log(`Hello ${newPerson.name}`);
  };
  return newPerson;
}

So instead of calling Object.create() all over the place you can simply call Person as a function and get back an object:

var me = Person("Valentino");

The constructor pattern helps encapsulating the creation and the configuration of a series of JavaScript objects.

And here again we have Person with the capital letter. It’s a convention borrowed from object oriented languages where classes have a capital letter. In JavaScript there are no classes but this style eventually made developers more comfortable.

Now the example above has a serious problem: every time we create a new object we duplicate greet() over and over. That’s sub-optimal. Luckily you learned that Object.create() creates links between objects and that leads to a nice solution. Let’s see what it is in the next section!

Refactoring the constructor function

First things first let’s move the greet() method outside, to an object on its own. You can then link new objects to that common object with Object.create():

var personMethods = {
  greet: function() {
    console.log(`Hello ${this.name}`);
  }
};

function Person(name, age) {
  // greet lives outside now
  var newPerson = Object.create(personMethods);
  newPerson.age = age;
  newPerson.name = name;
  return newPerson;
}

var me = Person("Valentino");
me.greet();

// Output: "Valentino"

How nice! But still we can do better. How about the good ‘ol “prototype” you saw earlier? Could help here?

Turns out, functions (and all the built-in objects) in JavaScript have a backpack called prototype. prototype is just another object and can contain everything we can think of: properties, methods. For adding a method to our Person prototype you can do:

Person.prototype.greet = function() {
  console.log(`Hello ${this.name}`);
};

and get rid of personMethods. The only problem now is that new objects won’t be linked automagically to a common ancestor unless we adjust the argument for Object.create:

function Person(name, age) {
  // greet lives outside now
  var newPerson = Object.create(Person.prototype);
  newPerson.age = age;
  newPerson.name = name;
  return newPerson;
}

Person.prototype.greet = function() {
  console.log(`Hello ${this.name}`);
};

var me = Person("Valentino");
me.greet();

// Output: "Valentino"

Now the source for all common methods is Person.prototype.

At this point we’re ready to do the last tweak to our Person because there is a cleaner way for arranging that function. With the new operator in JavaScript we can get rid of all the noise inside Person and just take care of assigning the arguments to “this”.

That means, the following code:

function Person(name, age) {
  // greet lives outside now
  var newPerson = Object.create(Person.prototype);
  newPerson.age = age;
  newPerson.name = name;
  return newPerson;
}

becomes:

function Person(name, age) {
  this.name = name;
  this.age = age;
}

And here’s the complete code:

function Person(name, age) {
  this.name = name;
  this.age = age;
}

Person.prototype.greet = function() {
  console.log(`Hello ${this.name}`);
};

var me = new Person("Valentino");
me.greet();

// Output: "Valentino"

Note that now you need to prefix the function call with “new”. That’s called “constructor call” and it’s the “standard” syntax for creating new shape of objects in JavaScript.

In other words, new does all the hard work for us:

  • creates a new blank object
  • links the object to the appropriate prototype
  • points this to the newly created object
  • returns the new object

Neat!

The secret life of JavaScript objects: checking the “linkage”

There are many ways for checking the link between our JavaScript objects. Object.getPrototypeOf for example is a method which returns the prototype of any given object. Consider the following code where Tom is created from a “Person” blueprint:

var Person = {
  name: "noname",
  age: 0,
  greet: function() {
    console.log(`Hello ${this.name}`);
  }
};

var Tom = Object.create(Person);

You can check if Person appears to be the prototype of Tom:

var tomPrototype = Object.getPrototypeOf(Tom);

console.log(tomPrototype === Person);

// Output: true

Object.getPrototypeOf works of course also if you constructed the object with a constructor call. But you should check against the prototype object, not on the constructor function itself:

function Person(name, age) {
  this.name = name;
  this.age = age;
}

Person.prototype.greet = function() {
  console.log(`Hello ${this.name}`);
};

var me = new Person("Valentino");

var mePrototype = Object.getPrototypeOf(me);

console.log(mePrototype === Person.prototype);

// Output: true

Besides Object.getPrototypeOf there is another method, isPrototypeOf. It checks whether the given prototype appears in the prototype chain of the object we’re checking against.

In the example above “me” is an object linked to Person.prototype. So the following check returns true:

var checkProto = Person.prototype.isPrototypeOf(me);
console.log(checkProto);

// Output: true

We could stop here but there is another surprise waiting for us …

The instanceof operator in JavaScript

There is also a third way for checking the link between JavaScript objects: it’s the instanceof operator.

In all honesty the name is a bit misleading because there are no “instances” in JavaScript. In a true object oriented language an instance is a new object created from a class. Consider the following example in Python. We have a class named Person and from that class we create a new instance called “tom”:

class Person():
    def __init__(self, age, name):
        self.age = age;
        self.name = name;

    def __str__(self):
        return f'{self.name}'


tom = Person(34, 'Tom')

Notice that in Python there is no new keyword. Now we can check whether tom is an instance of Person with the isinstance method:

isinstance(tom, Person)

// Output: True

Tom is also an instance of “object” in Python and the following code returns true as well:

isinstance(tom, object)

// Output: True

According to the documentation isinstance “Return true if the object argument is an instance of the class argument, or of a (direct, indirect or virtual) subclass thereof”.

So we’re talking about classes here. Now let’s see what instanceof does instead. We’re going to create tom starting from a Person function in JavaScript (because there are no real classes):

function Person(name, age) {
  this.name = name;
  this.age = age;
}

Person.prototype.greet = function() {
  console.log(`Hello ${this.name}`);
};

var tom = new Person(34, "Tom");

And now let’s use instanceof in a creative way:

if (tom instanceof Object) {
  console.log("Yes I am!");
}

if (tom instanceof Person) {
  console.log("Yes I am!");
}

Take a moment and try to guess the output. instanceof simply checks whether Person.prototype or Object.prototype appear in the prototype chain of tom. And indeed they are! The output is “Yes I am!” “Yes I am!”.

So here’s the key takeaway: the prototype of a JavaScript object is (almost) always connected to both the direct “parent” and to Object.prototype. There are no classes like Python or Java. JavaScript is just made out of objects. But since I mentioned it, what’s a prototype chain by the way?

What’s the prototype chain in JavaScript?

If you paid attention I mentioned “prototype chain” a couple of times. It may look like magic that a JavaScript object has access to a method defined elsewhere in the code. Consider again the following example:

var Person = {
  name: "noname",
  age: 0,
  greet: function() {
    console.log(`Hello ${this.name}`);
  }
};

var Tom = Object.create(Person);

Tom.greet();

Tom has access to greet() even though the method does not exists directly on the “Tom” object. How is that possible?

Unlike OOP languages like Python or Java where every child object gets a copy of all the parent’s methods, in JavaScript the relation works backward.

Children remain connected to the parent and have access to properties and methods from it. That’s an intrinsic trait of JavaScript which borrowed the prototype system from another language called Self.

When I access greet() the JavaScript engine checks if that method is available directly on Tom. If not the search continues up the chain until the method is found.

The “chain” is the hierarchy of prototypes objects to which Tom is connected. In our case Tom is an objects of type Person so Tom’s prototype is connected to Person.prototype.

Person.prototype is an object of type Object so shares the same prototype of Object.prototype. If greet() would not have been available on Person.prototype then the search would have continued up the chain until reaching Object.prototype. That’s what we call a “prototype chain”.

What is prototypal inheritance in JavaScript?

View this post on Instagram

🕵️‍♀️ What is "prototypal inheritance" in JavaScript? // "Prototypal inheritance" is a lie. I see a lot of JavaScript developers still confused by "prototypal inheritance". It's simpler than you think: there is no "inheritance". Just forget that sentence and remember that JavaScript objects are linked to other objects. It's a link. There is no inheritance. Object in JavaScript is the backbone of the language. Think of objects as of containers for keys and values. Objects have properties and may contain almost any JavaScript entity like other objects, numbers, strings, functions, and arrays. But there's more! JavaScript objects are most of the times linked to other objects via the so called "prototype chain". It's like a link, but working backward from "child" to "parent". When you create a new object with Object.create, the "child" objects is connected to the parent's prototype. That's it! There is no inheritance, just links! – To all the JavaScript developers: what's a JavaScript topic that still confuses you? Let me know and I'll got you covered! – Stay tuned and follow me for more JavaScript tidbits! . . . . . #application #buildtheweb #code #coder #codetips #valentinogagliardi #javascript #webdev #coding #codingisfun #codinglife #developer #developerslife #peoplewhocode #programmerrepublic #programming #es6 #web #littlejavascriptbook #softwareengineering #softwaredevelopment #100daysofcode #html #css #webplatform #teachingjavascript #piccololibrojavascript

A post shared by Valentino Gagliardi (@valentinogagliardi) on

You might have read the term “prototypal inheritance” in dozens of online tutorials.

I see a lot of JavaScript developers confused by “prototypal inheritance”. It’s simpler than you think: there is no “prototypal inheritance” in JavaScript. Just forget that sentence and remember that JavaScript objects are most of the times linked to other objects. It’s a link. There is no inheritance.

The secret life of JavaScript objects: why are we doing this?

At this point you might be asking “Valentino, why should I learn all that stuff?”. I strongly believe in the importance of learning JavaScript in depth and the reasons are manifold. In particular you can:

  • write idiomatic JavaScript
  • contribute better to JavaScript codebase
  • write more robust JavaScript applications
  • create (if you want) a well structured JavaScript library
  • read and understand other people’s code

Head over Github, find a JavaScript library you like and check out the source code. Most of the times you’ll see “SomeFunction.prototype” all over the place. Lightbulb moment!

“Protecting” JavaScript objects from manipulation

Most of the times it’s fine to keep JavaScript objects “extensible“, that is, making possible for other developers to add new properties to an object. But there are situations when you want to protect an object from further manipulation. Consider a simple object:

var superImportantObject = {
  property1: "some string",
  property2: "some other string"
};

Everybody can add new properties to that object:

var superImportantObject = {
  property1: "some string",
  property2: "some other string"
};

superImportantObject.anotherProperty = "Hei!";

console.log(superImportantObject.anotherProperty); // Hei!

Now suppose you want to protect the object from new additions: in jargon you want to prevent “extensions” to the object. You can call Object.preventExtensions on it:

var superImportantObject = {
  property1: "some string",
  property2: "some other string"
};

Object.preventExtensions(superImportantObject);

superImportantObject.anotherProperty = "Hei!";

console.log(superImportantObject.anotherProperty); // undefined

This technique is handy for “protecting” critical objects in your code. There are also a lot of pre-made objects in JavaScript that are closed for extension, thus preventing developers from adding new properties on them. That’s the case of “important” objects like the response of an XMLHttpRequest. Browser vendors forbid the addition of new properties on the response object:

var request = new XMLHttpRequest();
request.open("GET", "https://jsonplaceholder.typicode.com/posts");
request.send();
request.onload = function() {
  this.response.arbitraryProp = "messing with youuu";
  console.log(this.response.arbitraryProp); // undefined
};

That’s done by calling Object.preventExtensions internally on the “response” object. You can also check whether a JavaScript object is protected with the Object.isExtensible method. It will return true if the object is extensible:

var superImportantObject = {
  property1: "some string",
  property2: "some other string"
};

Object.isExtensible(superImportantObject) && console.log("Open for extension!");

or false if it is not:

var superImportantObject = {
  property1: "some string",
  property2: "some other string"
};

Object.preventExtensions(superImportantObject);

Object.isExtensible(superImportantObject) ||
  console.log("Closed for extension!");

Of course existing properties of the object can be changed or even deleted:

var superImportantObject = {
  property1: "some string",
  property2: "some other string"
};

Object.preventExtensions(superImportantObject);

delete superImportantObject.property1;

superImportantObject.property2 = "yeees";

console.log(superImportantObject); // { property2: 'yeees' }

Now, to prevent this sort of manipulation you could always define each property as not writable and not configurable. And for that there is a method called Object.defineProperties:

var superImportantObject = {};

Object.defineProperties(superImportantObject, {
  property1: {
    configurable: false,
    writable: false,
    enumerable: true,
    value: "some string"
  },
  property2: {
    configurable: false,
    writable: false,
    enumerable: true,
    value: "some other string"
  }
});

Or, more conveniently you can use Object.freeze on the original object:

var superImportantObject = {
  property1: "some string",
  property2: "some other string"
};

Object.freeze(superImportantObject);

Object.freeze does the same job of Object.preventExtensions, plus it makes all the object’s properties not writable and not configurable. The only drawback is that “freezing” works only on the first level of the object: nested object won’t be affected by the operation.

And now having shed some light on JavaScript objects, let’s talk about ES6 classes. What are they, really?

The secret life of JavaScript objects: class illusion

There is a huge literature on ES6 classes so here I’ll give you just a taste of what they are. Is JavaScript a real object oriented language? It seems so if you look at this code:

class Person {
  constructor(name) {
    this.name = name;
  }

  greet() {
    console.log(`Hello ${this.name}`);
  }
}

The syntax is quite similar to classes in other programming languages like Python:

class Person:
    def __init__(self, name):
        self.name = name

    def greet(self):
        return 'Hello' + self.name

or PHP (forgive me father):

class Person {
    public $name; 

    public function __construct($name){
        $this->name = $name;
    }

    public function greet(){
        echo 'Hello ' . $this->name;
    }
}

Classes have been introduced with ES6 in 2015. But at this point it should be clear to you that there are no “real” classes in JavaScript.

Everything is just an object and despite the keyword class the “prototype system” is still there. Remember, new JavaScript versions are backward-compatible. That means new feature are added on top of existing ones an most of those new feature are syntactic sugar over legacy code.

So what’s a class? There is a tool called Babel which helps developer to write modern JavaScript code and then run that code even in older browsers. In other words new syntax like ES6 class is transformed to a legacy version. In fact if you copy the Person class in the Try it out section of the Babel website you’ll get a Person function and a bunch of other methods. What a surprise!

In the end everything narrows down to prototypes, objects, and functions!

Where to go from here?

The quintessential this and Object prototypes by Kyle Simpson is one of the best books on the subject, Kyle goes even deeper into objects mechanic. I suggest reading that book after my introductory article.

I also have a book, The Little JavaScript Book, which I consider a book on the hard parts of JavaScript, while being still beginners friendly. Go grab your copy!

The secret life of JavaScript objects: wrapping up

Almost everything in JavaScript is an object. Literally. JavaScript objects are containers for keys and values and may also contain functions.

Object is the basic building block in JavaScript: it makes possible to create other custom objects starting from a common ancestor. Then we can link objects together by the means of an intrinsic trait of the language: the prototype system.

Starting from a common object we can create other objects sharing the same properties and methods of the original “parent”. But the way this works is not by copying methods and properties to every child, like OOP languages do.

In JavaScript every derived object remains connected to the parent. New custom objects are created either with Object.create or with a so called constructor function. Paired with the new keyword, constructor functions sort of mimic traditional OOP classes.

Thanks for reading and stay tuned on this blog!

3 Replies to “The Secret Life of JavaScript Objects: a Tale of Prototypes”

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.