Course: JavaScript

Progress (0%)

JavaScript Objects - Prototypes

Chapter 40 1 hr 42 mins

Learning outcomes:

  1. Recap of the problem with defining methods in a constructor's body
  2. What are prototypes
  3. The internal [[Prototype]] attribute
  4. The Object.create() method
  5. Prototype chains
  6. Property retrieval and assignment mechanisms
  7. Own vs. inherited properties
  8. The internal workings of the in operator
  9. The prototype property of functions
  10. Prototypal inheritance
  11. Retrieving prototypes via Object.getPrototypeOf() and __proto__
  12. Setting prototypes via Object.setPrototypeOf() and __proto__

Introduction

In the last chapter on constructors, we saw a decent amount of concepts tied to the main concept of a constructor function in JavaScript. Particularly, we saw what are constructors; how to create them; how to initialise objects out of them; check for instances of a constructor, and so on and so forth.

There we even came across the fact that defining instance methods from within the constructor function's body is generally not a good idea, and that the best way to create an instance method is to leverage the prototype.

So what exactly is a prototype in JavaScript?

This chapter aims to answer this question to its very core and in the finest of details.

By the end of this chapter, it's a guarantee that you'll know about the notion of a prototype, when to use it, how to use it, many related terms such as inherited properties, and much much more.

Alright, it's time to dive right in...

Defining methods inside constructors

Before we begin, let's quickly recap the problem with defining an instance method in the body of a constructor function. This will allow us to better appreciate the significance of prototypes.

Shown below is the code snippet that we wrote in the previous chapter:

function Point(x = 0, y = 0) {
    this.x = x;
    this.y = y;

    this.setTo = function(x, y) {
        this.x = x;
        this.y = y;
    }
}

Can you recall the problem in here?

Well, setTo() is a method which merely repositions the given Point instance to another set of coordinates. It behaves the same way for each and every Point instance, yet our code creates a new setTo() method for each new instance.

That is, if we have ten Point instances, then each of them has its own setTo() method, constituting a total of ten different setTo() methods in the application (all doing exactly the same thing)!

This is the problem. We are repeating stuff.

Recall that we prevented this repetitive function creation by defining the function once in the global scope and then assigning it to this.setTo inside the constructor, but this had its downsides as well.

Firstly there is still a separate setTo property for each instance, even though it holds the same function being created; secondly the global scope is now being polluted.

We even laid a couple of solutions to this global scope–pollution problem but all of them led to only one path and that was more headache.

Read more about these problems in the section Problem with constructors in the last JavaScript Objects — Constructors chapter.

Long story short, the simplest and most efficient way to create instance methods in JavaScript is to refrain from using the constructor function's body (in almost all cases) and instead use prototypes.

Let's explore them...

What is a prototype?

JavaScript, as we already know by this point, is an object-oriented programming language. It's essentially built on the idea of objects.

Now OOP languages can be divided into two categories: classical OOP languages (a.k.a. class-based languages) for e.g. C++, Java, Python; and prototypical OOP languages (a.k.a prototype-based languages) for e.g. Self, JavaScript.

JavaScript, as we know, is a prototype-based OOP language.

In classical OOP languages, classes inherit data from other classes. Instance objects created out of these classes essentially don't inherit data from other objects.

In prototype-based languages, the notion of inheritance is surely there, but in a different way. Classes don't just exist in these languages so there's no point of thinking about what happens with them.

In prototype-based languages, objects inherit data from objects.

This leads us to the simplest definition of what a prototype is:

For a given object o, the object from which o inherits properties is called the prototype of o.

That's just it!

As always, let's understand this definition in more detail.

If we consider any given object o, let's say the array [1, 2, 3] or the object {x: 0, y: 0}, then the object from which o inherits properties is called the prototype of o.

Suppose that p is this prototype object. Then any properties defined on p would be available on o as well, since they are inherited by o.

But what exactly does it means by 'inherits' in the context of objects in JavaScript?

Formally defining 'inherits' in relation to JavaScript's objects right now would be much more of a jargon than a help, hence, we would demonstrate a simple example to explain it.

Let's say we have two objects a and b as shown below:

var a = { x: 10, y: 20 };
var b = { p: 100, q: 200 };

If we assume that a is the prototype of b, which isn't explicitly shown in this code snippet in any way (i.e. it's just a supposition), then here's what would happen when we access a couple of properties on b.

  1. b.p would simply be 100.
  2. b.q would be 200.
  3. b.x would be... Hmm. What do you think? Well, b.x would be 10 and you might have already been able to see where this value is coming from — it's being inherited from a.
  4. b.y would be 20, once again thanks to inheritance.

At the very foundation, this is just what prototypes are all about — that is, inheritance. One object has access to all the properties of its prototype by means of inheritance.

That's it!

There is no rocket science at all involved in prototypes in JavaScript, as you may have thought of when going through online resources teaching prototypes, or from your colleague developers.

Prototypes are superbly easy, and that's a fact!

But the applications of prototypes in JavaScript, plus a couple of utilities that revolve around them, are altogether not that easy to understand at first glance — they require a little more attention.

But, no worries. We'll discuss each and everything in the simplest of words to make sure that you end this chapter as a prototype pro.

Let's explore more about prototypes in JavaScript...

The [[Prototype]] attribute

So far, we've learnt that an object in JavaScript inherits data from another object called its prototype. Fair enough.

But let's pause here for a moment and think about this definition once more.

An object inherits data from its prototype. OK.

But how does it know of its prototype in the first place? In other words, how does any given object know that it will be inherting properties from another given object?

Well, this really is a nice observation. And the good news is that the answer is quite straightforward.

It turns out that in JavaScript, as specified in section 10.1 of the ECMAScript spec, every single object (yes that's right, every single object) has an internal attribute called [[Prototype]] that simply holds a reference to the prototype of that object.

Every object in JavaScript has an internal [[Prototype]] attribute which contains a reference to its prototype.

In simpler words, all objects in the language inherit properties from their [[Prototype]] attribute, which simply points to their prototype object.

Easy?

Going with our old example of the object a and b, as follows:

var a = { x: 10, y: 20 };
var b = { p: 100, q: 200 };

where b's prototype is a, the object b would internally look something like this:

// internal representation of b
b: {
    p: 100,
    q: 200,
    [[Prototype]]: a
}

First it contains its own properties p and q and then an internal attribute [[Prototype]] pointing to its prototype, which in this case is a.

Let's consider a more familiar example.

We all are used to creating arrays, and literal objects from the previous part of this course.

The moment we create an array using the literal notation [] or via the Array() constructor, JavaScript creates an Array instance whose prototype is configured automatically.

For instance, given the array arr below:

var arr =  [10, -5, 60];

if we were to show its internal representation, it would be as follows:

// internal representation of arr
arr: {
    0: 10,
    1: -5,
    2: 60,
    length: 3,
    [[Prototype]]: Array.prototype
}
This is not a complete illustration of all the internal attributes of an array, or an object in general. For now, we're only concerned with [[Prototype]] and hence only showcase that for simplicity.

The first three properties are merely elements of the array, the fourth property is the length of the array, and finally the last one is its internal property [[Prototype]] holding the prototype of the array object.

This prototype turns out to be Array.prototype i.e. the prototype property of the Array constructor.

Later on in this chapter, we'll see the whole idea behind the prototype property of constructor functions and how it enables JavaScript to emulate classes from classical OOP languages along with the notion of constructor functions themselves.

Let's consider another example.

When we create an object via the object literal syntax, or equivalently via the Object() constructor, JavaScript creates an Object instance whose prototype is automatically set to Object.prototype:

Hence, given the code below:

var obj =  { x: 0, y: 0 };

its internal representation would be something as follows:

// internal representation of obj
obj: {
    x: 0
    y: 0,
    [[Prototype]]: Object.prototype
}

The object obj would have access to all the properties defined on Object.prototype.

Once again, we'll explore Object.prototype, and the prototype property of constructors in general, later on in this chapter.

In short, every single object in JavaScript has a corresponding prototype from which it inherits properties, and this prototype is stored in that object's internal [[Prototype]] attribute.

Simple!

Now sometimes it might be the case that an object doesn't want to inherit any properties from another object. In other words, it might be the case that the object doesn't want to have a prototype.

But this doesn't seem possible because every object in JavaScript is obliged to have a prototype. Now what?

Well, the solution quite straightforward — the object has its prototype as null.

The prototype is effectively still there on the object, i.e. its [[Prototype]] attribute has a value at the end of the day, but it's null, signaling that the object doesn't inherit any properties.

In JavaScript, there is only one predefined object that has a null prototype and that is Object.prototype.

However, as we shall see in the next section, we could create any custom object with null as its prototype.

[[Prototype]] is merely a spec feature!

Note that this notation of [[Prototype]] is merely an imaginative idea, purely for expository purposes — in reality there is nothing such as [[Prototype]] in implementations of JavaScript.

All major implementations, including those in Google Chrome, Firefox, Safari, Edge, etc, have sophisticated ways to resolve the prototype of any arbitrary object, amidst numerous optimizations. The way each of these implementations stores these prototype references is purely local to the respective implementation itself.

The ECMAScript spec uses this internal attribute notation (i.e. [[InternalAttribute]]) to be able to easily and clearly explain stuff — JavaScript engines are free to use any way they desire to implement that stuff, given that they remain consistent with the behavior as defined in the spec.

The Object.create() method

In the example given in the What is a prototype section above, where we defined two object literals a and b, we assumed that a was the prototype of b — in the code itself, there was nothing actually implementing this.

Now, using the method Object.create(), we shall actually build this prototype relationship between a and b.

The static Object.create() method was introduced in ECMAScript 5 as a way to create a new object with a given prototype.

Here's its syntax:

Object.create(prototype[, propsObj])

The prototype of the object to be created is given as the first arg to Object.create().

The second propsObj arg specifies the initial properties of the object to be created. As one might think, this arg is not an object mapping keys to values, but rather an object mapping keys to property descriptors. We'll see what this means in the chapter JavaScript Object Methods.

The secong parameter of Object.create() is not very frequently used.

In an upcoming exercise, we get you to implement a polyfill for Object.create() purely using the idea of a constructor function.

Anyways, let's now put Object.create() into action.

First, let's consider the object a that has to be made the prototype of b:

var a = { x: 10, y: 20 };

Now, let's consider the object b:

var b = { p: 100, q: 200 };

Stating it once more, a has to be made the prototype of b. Currently there is nothing implementing this in the code.

So how do you think could this be done using Object.create()?

Well, one thing that has to be realized over here is that we want to change the prototype of an existing object (b in this case). However, Object.create() only enables us to create a new object with a given prototype.

Hence, we couldn't just take b and magically set a as its prototype using Object.create(). There is just no way to do so, at least using Object.create().

Instead, we have to first create an empty object using Object.create() whose prototype is configured to a, save that object in b, and then add the properties of b as specified in the code above one-by-one using the dot notation (or bracket notation) property assignment syntax.

Let's see this in terms of code:

var a = { x: 10, y: 20 };

// make a as the prototype
var b = Object.create(a);

// add the properties one-by-one
b.p = 100;
b.q = 200;

Here's what's happening in this small piece of code:

First of all, a global variable a is created and assigned the object { x: 10, y: 20 }. Next, a global variable b is created and assigned the value Object.create(a). This method call effectively creates a new empty object whose prototype is set to a.

Finally, we add two properties p and q to b and set them to 100 and 200, respectively.

The heart of this code lies in line 4 — it's where an inheritance relationship is built between b and a.

Let's throw in a couple of console.log() statements here and there in this code snippet and thus inspect the object b more precisely:

var a = { x: 10, y: 20 };

// make a as the prototype
var b = Object.create(a);

console.log(b);

console.log('b.x:', b.x);
console.log('b.y:', b.y);

// add the properties one-by-one
b.p = 100;
b.q = 200;

console.log('b.p:', b.p);
console.log('b.q:', b.q);
{} b.x: 10 b.y: 20 b.p: 100 b.q: 200

The first log tells us that Object.create(a) simply creates an empty object (whose prototype is a).

The second and third logs inspect the values of the properties x and y on b. These properties don't directly exist on b. However, they exist on the prototype of b, i.e. the object a. Hence, they are ultimately accessible on b as well.

The final two logs simply inspect the values of the properties p and q on b, which are its own properties and simply resolve down to 100 and 200.

As you may have already noticed in the code above, using Object.create() doesn't allow us to conveniently initialise the object to-be-created with a given set of properties. That is, we have to manually go on and add each property one-by-one after the object is created.

Although this isn't still much of a big problem, it is an inconvenience at the end of the day if all we need to do is quickly initialise the newly-created object with a literal notation.

However, as we shall see later on, this inconvenience becomes almost insignificant when we are defining methods on the newly-created object, since methods have to hold on a function expression and aren't usually defined in one flow (i.e. they usually have bodies spanning multiple lines) as compared to other values that could be defined in a flow.

Object.create() could be called with null as an arg as well.

In that case, a new object is created (and returned) whose prototype is null. That is, this object does not inherit any properties since it doesn't have a prototype.

Consider the following code:

// create an object with a null prototype
var o = Object.create(null);

o.x = 10;
o.y = 20;

console.log(o);
{x: 10, y: 20}

Here, we create an object using Object.create(null) whose prototype is null and then assign it to the variable o. Next, we add two properties x and y to this object and then log it.

Remember that o is still an object and therefore could have properties. It's just that its [[Prototype]] is null.

Prototype chains

Let's appreciate the fact that the prototype of any given object is also an object at the end of the day. Likewise, as we said before that every single object in JavaScript has a corresponding prototype, it means that a prototype object would have a prototype as well.

Doesn't it?

This takes us to the definition of another term — prototype chain:

For a given object o, its prototype chain is simply a list of prototypes whose first item is the prototype of o, and any subsequent item is the prototype of the previous item, and the last item is simply null.

The prototype chain is simply a list that specifies the prototype of an object, then the prototype of that prototype, then the prototype of the prototype of that prototype, and so on.

This is quite a natural concept noticeable in some real life scenarios. For e.g. we inherit genetics from our parents, and our parents inherit genetics from their parents, and so on and so forth.

Let's consider an example.

In the code below, we define an object a, then an object b whose prototype is a, and finally an object c whose prototype is b:

var a = { x: 10, y: 20 };
var b = Object.create(a);
var c = Object.create(b)

With this code in place, we'd write the prototype chain of c as follows:

ba

This means that c inherits data from b which in turn inherits data from a. Note how the arrow start at b and points to a. This just follows from the fact that b contains a [[Prototype]] internal attribute that points to a.

But wait... The chain seems incomplete. We've not stated the prototype of a in the chain.

Well, you're absolutely right!

As we stated before, when we create an object using the object literal syntax, its prototype is automatically set to Object.prototype. Hence, in our case, a inherits from Object.prototype, which in turn has a null prototype.

Thus, the complete prototype chain of c would look like this:

baObject.prototypenull

The idea of prototype chains in JavaScript is of practical importance to the language in resolving properties on objects.

Let's see what this means...

Property retrieval mechanism

When we retrieve a property on an object in JavaScript, there goes, in effect, a whole bunch of steps in the background in order to resolve the property.

Let's see an example.

Suppose we have three objects o1, o2 and o3 as shown below:

var o1 = { a: 100, b: 200, c: 300 };
var o2 = { a: 10, b: 20 };
var o3 = { a: 1 };

Also suppose that o3 inherits from o2, and that o2 inherits from o1. Describing this visually, the later-defined objects in the code inherit from the earlier-defined objects.

Now, let's see what a couple of property access expressions on o3 resolve down to:

o3.a returns 1; o3.b returns 20; o3.c returns 300; o3.nonExistent returns undefined.

Let's see the same for the object o2:

o2.a returns 10; o2.b returns 20; o2.c returns 300; o2.nonExistent returns undefined

And now finally for the object o1:

o1.a returns 100; o1.b returns 200; o1.c returns 300; o1.nonExistent returns undefined;

Did you notice any pattern?

Whenever a property is accessed on a given object in JavaScript, if that property exists on the object, then it's used to resolve the property-access expression.

Otherwise, the property is searched for on the prototype. If it exists there, the original property-access expression of the object is resolved with that value. Otherwise, searching moves to the next prototype down the chain, and then the next, and so on.

This searching stops when the property is ultimately found on a prototype or when the null prototype is reached while traversing the prototype chain. When the null prototype is reached, that means that the property wasn't found anywhere, and likewise undefined is returned.

This is the property resolution algorithm (given quite generically) employed by JavaScript when we access a property on a given object.

One of the biggest takeaways from this property resolution mechanism is that properties defined on an object shadow properties available on its prototype. This is formally referred to as property shadowing.

For instance, in the code above, the property a of o3 shadows the property a of o2 in the expression o3.a. Similarly, the property b of o2 shadows the property b of o1 in the expression o2.b.

Anyways, practically speaking, this model allows JavaScript to emulate class-subclass-subsubclass relationships from classical OOP languages, and with even more flexibility than in those languages.

The notion of property retrieval is quite intuitive and easy to understand as you just saw above. However, property assignment in JavaScript isn't that obvious and intuitive in many aspects.

Property assignment mechanism

As a developer, it's important for us to be aware of some very surprising cases when assigning properties to objects so that our applications don't produce any kind of bugs or weird behavior.

Let's see how property assignment works in JavaScript.

Say we have an object o with an own property prop. If the property is a non-writable data property or a setter-less accessor property of the object o itself (is o's own property), what do you think would happen to the property assignment expression shown below?

o.prop = value;

Well, if the script is running in strict mode, we'll get an error. Otherwise, the property assignment will go silently ignored.

Quite basic.

Now, the surprising thing in JavaScript is that this notion extends to the prototype chain of the object o; not just on the object itself.

That is, if the property doesn't exist on the object itself, but does exist on some object in its prototype chain, then the same rule as shown above applies. In other words, if the property prop is an inherited non-writable data property or an inherited setter-less accessor property, it's invalid to assign a value to that property on o.

Let's actually demonstrate this.

First, we'll see the simplest case — when the property is the object's own data property or own accessor property:

var o = {};

// non-writable data property
Object.defineProperty(o, 'x', { value: 'old' });

// setter-less accessor property
Object.defineProperty(o, 'y', {
    get: function() { return 'old'; }
});

o.x = 'new';
console.log('o.x:', o.x);

o.y = 'new';
console.log('o.y:', o.y);
o.x: old o.y: old

As you can see here, both the property assignment expressions, in lines 11 and 14, have no effect. If this script was running in strict mode, we'g get an error thrown on the very first property assignment expression in line 11.

Now, let's see the case where the property isn't the object's own property but rather an inherited property:

var o = {};

// non-writable data property
Object.defineProperty(o, 'x', { value: 'old' });

// setter-less accessor property
Object.defineProperty(o, 'y', {
    get: function() { return 'old'; }
});

var a = Object.create(o);

a.x = 'new';
console.log('a.x:', a.x);

a.y = 'new';
console.log('a.y:', a.y);

console.log(a);

Everything is same here as before, except for the fact that now the property assignment expressions (in lines 13 and 16) are operating on the object a, not on o. The object a's prototype is o.

Now the most surprising thing is the output of this code:

a.x: old a.y: old {}

As we know from the code above, there are no such properties as x and y on the object a, and so we might expect the expressions a.x = 'new' and a.y = 'new' to create those properties on a.

This is NOT the case.

Instead, property assignment expressions also involve a search for the property's key on an object and, if not found, then on the prototype chain of that object.

This explains why a.x = 'new' has no effect at all (or throws an error if our script was in strict mode). The property x is found on the prototype of a, i.e. the object o, where it is configured as non-writable. Likewise, JavaScript disallows the property to be assigned a value to, even on the derived object a.

A similar reasoning applies to a.y = 'new'. The property y is searched for on a, and then on its prototype, i.e. the object o, where it's found to be an accessor property without a setter function. Hence, JavaScript simply ignores the statement a.y = 'new' (or throws an error if in strict mode) just as it would've if y were a's own setter-less accessor property.

Note that if the inherited accessor property y here (defined on the object o) had a setter function, quite obviously, it would've been called in executing a.y = 'new'.

This can be seen as follows:

var o = {};

// non-writable data property
Object.defineProperty(o, 'x', { value: 'old' });

// setter-less accessor property
Object.defineProperty(o, 'y', {
    get: function() { return 'old'; },
set: function(value) {
console.log('Setter called with value:', value);
} }); var a = Object.create(o); a.x = 'new'; console.log('a.x:', a.x); a.y = 'new'; console.log('a.y:', a.y); console.log(a);
a.x: old Setter called with value: new a.y: old {}

Clearly the inherited property's setter is called by the statement a.y = 'new', as is apparent by the second log.

In both of these code snippets, also take note of the last log, i.e. {}. It effectively shows the object a after the property assignment statements are executed. It's empty, which clearly indicates that the property assignment expressions don't create the respective properties on a.

In real-world applications, this idea is used quite extensively — even in some of the predefined APIs exposed by JavaScript.

The idea of non-writable data properties on the prototype preventing the assignment of the identically-named property on any of the derived objects is not employed frequently. The reason for this is very clear, and we've stated is many times in this and the previous chapter.

Data properties, that directly contain given data, are only meant to denote the traits of an object, and are therefore meant to be defined on instances directly, NOT on their prototypes.

In contrast to this, when we consider the behavior of instances (i.e. some kind of functions), they are typically defined on the prototype of those instances.

And as we know, accessor properties are merely a decoration over using two different methods to accomplish a task on an object. For instance, instead of defining a getX() and setX() method on a Point object, we could just define an accessor property x with a given getter and setter function to take care of that property's retrieval and assignment, respectively.

This effectively means that we could define accessor properties on an instance's prototype and thus get its functionality to be used by all instances.

Keep in mind that the same feature could be achieved using instance methods defined on the class — the accessor property feature merely provides a more convenient interface to get and set a value, which really makes sense when the property's name is a noun.

To recap it, a property assignment on an object would have no effect (in non-strict mode) or throw an error (in strict mode) if the property is a non-writable own/inherited data property or a setter-less own/inherited property.

If this ain't the case, then if the property is an own/inherited accessor property with a setter function, then the property assignment would invoke this setter function with the assigned value.

And if this ain't the case as well, then the own data property is merely created or updated, depending on whether the property existed previously.

A quick summary

For a given object obj, a given property prop and a given JavaScript expression value, how to resolve the property assignment expression shown below:

obj.prop = value

Well, we've learnt exactly this very thing in the discussion above — there are a handful of cases the engine has to consider before completely executing the assignment statement.

The table below nicely highlights all this information.

Own or inherited?Data or accessor property?Is writable?Has setter?Result
OwnDataYesSet obj's own property prop to value.
OwnDataNoIgnore the property assignment (in non-strict mode) or throw an error (in strict mode).
OwnAccessorYesInvoke obj's own property prop's setter function with value as arg.
OwnAccessorNoIgnore the property assignment (in non-strict mode) or throw an error (in strict mode).
InheritedDataYesCreate obj's own property prop and set it to value.
InheritedDataNoIgnore the property assignment (in non-strict mode) or throw an error (in strict mode).
InheritedAccessorYesInvoke obj's inherited property prop's setter function (obviously defined on some object in obj's prototype chain) with value as arg.
InheritedAccessorNoIgnore the property assignment (in non-strict mode) or throw an error (in strict mode).
None, i.e. does not existNoCreate obj's own data property prop and set it to value.

Own vs. inherited properties

An object in JavaScript inherits properties from its prototype which in turn inherits properties from its prototype, which inherits properties from its prototype, which once again inherits properties from its prototype, and so on and so forth.

If a given property exists directly on an object, it takes precedence over the same property somewhere in the object's prototype chain, when accessed on the object.

For instance, if obj is {x: 0} and proto is {x: 10, y: 10}, where proto is the prototype of obj, then obj.x would return 0 since x exists on obj itself and thus takes precedence over the property x of proto.

Recall that this phenomenon is known as property shadowing i.e. the property x of obj shadows the property x of proto in the expression obj.x.

Now for a given object, this distinction between those properties that are defined directly on the object vs. those that are defined somewhere in its prototype chain is important.

A handful of utilities are given to us in JavaScript to allow us to be able to establish this distinction for a given property actually in code.

But first let's talk about the distinction in more precise terms.

A property that is accessible on an object could be its own property or an inherited property.

For a given object, any property that's defined directly on the object is called its own property.

For instance, going with the example above, if obj is {x: 0}, then x is obj's own property.

Similarly,

For a given object, any property that's defined somewhere in its prototype chain, but not on the object itself, is called its inherited property.

Inherited properties are sometimes also known as shared properties. This term comes from the fact that these properties are shared by objects inherting from the prototype on which these properties are defined.

As we've seen before, it's not necessary for an object's inherited property to be coming directly from its prototype — the property might be coming from the very last object in the prototype chain.

If a property is ultimately accessible on an object (by virtue of the object itself or its prototype chain) and if that property is not the object's own property, then it's known for sure that it is an inherited property.

Note that if a property is not an object's own property, then it doesn't have to be the case that is is an inherited property — it might just not exist on the object or its prototype chain at all.

The hasOwnProperty() method of objects helps us determine whether a given property is an object's own property.

obj.hasOwnProperty(propName)

The object obj whose property ought to be inspected is the caller of the method while the property's name is passed as an arg to the method.

The return value of hasOwnProperty() is the Boolean true if the given property is obj's own property, or else false.

Let's try this method:

In the code below, we define an object a and then inspect it using its hasOwnProperty() method:

var a = { x: 0, y: 0 };

console.log(a.hasOwnProperty('x'));
console.log(a.hasOwnProperty('y'));
console.log(a.hasOwnProperty('z'));
true true false

Apparently, the first log is true simply because x is a's own property. And so is the property y. However, z is not a's own property and likewise we get false in the last log.

Let's introduce a prototype explicitly into this code and then carry out one additional hasOwnProperty() inspection:

var proto = { z: 0 };

var a = Object.create(proto);
a.x = 0;
a.y = 0;

console.log(a.hasOwnProperty('x'));
console.log(a.hasOwnProperty('y'));
console.log(a.hasOwnProperty('z'));

console.log(proto.hasOwnProperty('z'));

Note that the object a here has the same properties as before — it's defined differently (i.e. not in a literal way) due to being created via Object.create().

The output of this code is as follows:

true true false true

The first three logs are the same as before. The fourth log determines whether z is proto's own property, and since it is, the output of the log is true.

Easy?

Let's take a quick test of yours.

Given the code below, what would o.hasOwnProperty('x') return?

var o = {};

Object.defineProperty(o, 'x', {
    value: 0
});
  • true
  • false

Prototypes and the in operator

We saw the in operator in the Objects Basics chapter, at the very start of this unit. It determines whether a property is in an object or not.

Well, that's an understatement.

Precisely speaking, the in operator, operating on an object and a property name, determines if the property is the object's own or inherited property. In other words, in simply tells us whether a given property is accessible on an object.

This means that starting from the object itself, it effectively traverses the whole prototype chain of that objet in search of the property, until it's found.

Consider the following code:

var proto = { y: 0 }

var o = Object.create(proto);
o.x = 0;

console.log('x' in o);
console.log('y' in o);

console.log('hasOwnProperty' in o);

console.log('nonExistent' in o);
true true true false

The first log determines whether x is accessible on the object o, and since it is, we get true output. The second log determine whether y is accessible on o, and once again since it is, we get another true output.

The third log might be counter-intuitive — we've not defined any hasOwnProperty on o, or its prototype proto, yet we have access to it as determined by the in operator.

As we'll soon see in detail, this hasOwnProperty property is coming from Object.prototype which in this case is the prototype of proto (and every object created via {} or new Object()).

The final log outputs false because the given property nonExistent doesn't exist on o, nor on any object in its prototype chain.

Simple.

The in operator together with hasOwnProperty() can be used to determine if an arbitrary property of a given object is its own property, inherited property, or simply a non-existing property.

This implementation of this is left as an exercise in the upcoming part of this unit. If you want to go for it right now, head over to Objects — Property Check Exercise on the next page.

The prototype property

Back in the last chapter, we showed the steps taken internally by the JavaScript engine when a constructor function is called, i.e. with the new keyword.

Let's recall those steps:

Given a function F, the expression new F() executes the internal [[Construct]] method on F that performs the following steps:

  1. A new empty object is created.
  2. The prototype of this object is set to F.prototype. We'll understand this step much better once we learn about prototypes in the next chapter.
  3. The [[Call]] internal method of the function is executed with its this set to the object created in step 1.
  4. The object created in step 1 is returned.

Step 1 is quite easy to understand — it merely creates the most atomic of JavaScript's data types, i.e. an object. Step 2, however, was vague at least uptil that chapter. Now, we'll unravel the whole idea behind it.

When a given function F is called as new F(), then as we already know, we get back a new object returned — or better to say, an instance of F().

This instance has its prototype set to F.prototype i.e. to the prototype property of F, automatically during the instantiation process.

So what is F.prototype for this function F?

Well, as one might think at the first glance (even as I did initially when learning JavaScript), F.prototype seems to take us to the prototype of F (remember that F is a function object).

That's completely wrong!

The term 'F.prototype' seems to be confusing and misleading.

To simplify this, as a rule of thumb, always remember that there is no standard way in JavaScript to retrieve the prototype of an object via a property on that object.

There is a non-standard property called __proto__, but once again, it's not a standard way. We'll learn more about __proto__ later in this chapter.

That basically eliminates the thought of F.prototype being the prototype of F. A big no.

Let's now see what F.prototype is.

F.prototype is just a convenient (and frankly speaking, a clever) way to denote the prototype of any instance of the constructor F().

Simple!

For the function F itself, F.prototype is nothing (literally nothing) more than a property whose value is an object. There is nothing special about F.prototype from the perspective of F itself.

But from the perspetive of an instance of F(), F.prototype has a special meaning. That is, it's the prototype of that instance (and all other instances of F()).

The prototype property of functions objects is one of the most useful and powerful concepts of JavaScript. Tons and tons of utilities in the whole language are defined on prototype properties of given functions.

The prototype property is what will ultimately be used to solve the problem that we encountered in the previous chapter of defining a method inside the body of a constructor function.

Consider the simple Point() constructor below, without the setTo() method's definition inside it:

function Point(x = 0, y = 0) {
    this.x = x;
    this.y = y;
}

Alright, now let's apply all our knowledge about prototypes to define setTo(). But not so quickly — we encourage you to think about the solution first.

Where to define the setTo() method?

From all the discussion we've had so far, we know that Point.prototype points to an object that is the prototype of every Point instance. That is, a Point instance inherits properties from Point.prototype.

Thus, if we define the setTo() method on the object Point.prototype, then every Point instance would have access to it. In other words, we'd be able to do something like p1.setTo() if we assume that p1 is a Point instance.

Voila!

We have solved our method definition problem.

Shown below is the complete code:

function Point(x = 0, y = 0) {
    this.x = x;
    this.y = y;
}

Point.prototype.setTo = function(x, y) {
    this.x = x;
    this.y = y;
}

The setTo() method is defined on the Point.prototype object. As a result, it's available to all Point instances.

Below we test the setTo() method on an instance p1:

var p1 = new Point();
undefined
p1.x
0
p1.y
0
p1.setTo(5, 15)
undefined
p1.x
5
p1.y
15

Yup, it works!

Let's see the benefits of using Point.prototype to define setTo():

  1. We aren't creating a new setTo() function for each new Point instance. The function is defined once and saved under Point.prototype.
  2. We aren't creating a new setTo() property for every single Point instance. The property is defined exactly once on the object Point.prototype and from there ultimately finds its way in the resolution of setTo as accessed on any Point instance.
  3. We aren't filling up the global scope in any way — all Point-related functionality is nicely within the Point function object.

Overall, this means that using the prototype to define instance methods is memory-wise much more efficient than using the constructor's body, and also much better in terms of readability and maintainability. For e.g. in the case of any errors or weird behavior with a Point instance, we know that we ought to look in the Point function object (either in its body or in Point.prototype).

Amazing!

Let's see another example, this time involving an accessor property on the prototype.

Suppose we have an online grocery store application with each item of the store represented by the class item. For the sake of clarity, we'll abstract away any lower-level details stored for each item such as ID or its category (such as fruits, vegetables, dairy etc.).

Each item has two data properties: actualPrice that gives the item's actual price (before any discounts) and sellingPrice that gives its current selling price, and finally an accessor property discount that gives the discount value on the item as a percentage value.

The point of giving discount as an accessor property and not as a data property is to keep from saving data redundantly in memory. If we know the actual price of an item and its current selling price, we could easily calculate the discount from these two values — there's no point of saving it separately.

Moreover, the point of giving discount as an accessor property and not as two separate methods (let's say getDiscount() and setDiscount()) is to keep the interface simple. The word 'discount' is a noun and nouns go well as properties of a class in OOP, not as methods.

Verbs go well as methods in OOP.

Time to implement the Item class:

function Item(sellingPrice, actualPrice) {
    this.sellingPrice = sellingPrice;
    this.actualPrice = actualPrice;

    Object.defineProperty(this, 'discount', {
        get: function() {
            return (this.actualPrice - this.sellingPrice)
                     / this.actualPrice * 100;
        },
        set: function(perc) {
            this.sellingPrice = this.actualPrice
                                      - perc / 100 * this.actualPrice;
        },
        configurable: true,
        enumerable: true
    })
}

Now, let's create an Item instance with supposed actualPrice and sellingPrice values and then get its discount:

var item = new Item(25, 50)
undefined
item.sellingPrice
25
item.actualPrice
50
item.discount
50

Getting is not really surprising at all, as we've discussed before.

The real surprise, and power, lies in setting values to inherited accessor properties.

In the code below, we aim to set 30 as the discount of the Item instance item.

As stated before, the real surprise here is that the expression item.discount = 30 doesn't create a new own property discount on item but rather delegates the property assignment to the prototype of item i.e. the object Item.prototype, where it ultimately results in the accessor property discount's setter being invoked.

Great!

This is the power of the prototype model employed by JavaScript. Objects inherit stuff directly from other objects. How simple, yet how strong as an idea. Wow!

What we've just shown is merely the start of this prototype potential. Things will become more interesting and more complex when we extend our knowledge to prototypal inheritance.

But before that, let's discuss about a key method used in prototypal inheritance — Object.create().

Prototypal inheritance

In the OOP world, a class can be based on another class and thus inherit stuff from it. For example, cats are animals and thus we could say that the Cat class is based on the class Animal.

The beauty of OOP is that one could build these inheritances as deep as desired and thus nicely model many objects (and their relationships) in real-life, and most importantly in the imaginary, computer-life.

For example, as we saw in the last chapter, a graphics drawing software could have a class Item to represent items in the application's canvas, a class Shape based on Item to specifically represent shapes such as rectangles, circles, polygons etc, and maybe even a class Square based on Rectangle to represent squares.

In the section above, we saw how to define a constructor and then configure the prototype property of that constructor to hold all its instance methods.

In this way, we said that a constructor function in JavaScript acts pretty much like a class from a traditional OOP language.

But as we know at this point, classes in classical OOP languages could inherit from given classes. For example, if the class Cat has a method called meow() and the Animal class has a method called walk(), then a Cat instance would be able to both meow() and walk(). In other words, a Cat would have all the behavior of an Animal.

The question is, can we do this in JavaScript? Can we use its prototype mechanism to emulate class-subclass inheritance?

Well, once again, we'll first let you think about this...

So what is your thought. Yes or no? Can JavaScript's prototype model emulate class-subclass inheritance?

We've already seen that it could completely emulate a class.

Well, to end the anticipation, yes, we could do this in JavaScript.

In fact, JavaScript's predefined APIs are built around the idea of classes inheriting from classes. The Number class inherits from Object, and so does String, Boolean, Array — they all are based on the Object class.

Let's see how exactly could we do this with a concrete example.

In the previous chapter, we came up with the idea of an imaginary drawing application where people could draw simple shapes, color them, add text, and so on; pretty much like a lite version of a full-fledge graphics editing software.

We drafted two specific classes in the app i.e. Rect to denote rectangles and Shape to denote shapes. We said that since rectangles are shapes, Rect inherits from Shape.

Up until the previous chapter, we were only able to model the state of these classes i.e. the instance properties, since we weren't introduced to prototypes. Now, we shall define some hypothetical methods on both of them and define an inheritance relationship between the classes.

So first thing's first, let's come up with a couple of methods for Rect and Shape.

If this were real app, we should be able to move a given shape any where on the canvas (or simply the screen) by dragging and then panning the element using the mouse pointer. This hints to us that move() could be an instance method of the class Shape.

Let's define another method. It might be possible to delete a shape by pressing the Del button while that shape is selected. This hints to us that delete() could be another Shape method.

For now, let's just define these methods hypothetically. We still don't know how would a shape actually be constructed in the app. So after all we couldn't really implement each of these methods move() and delete(). We'll just use simple console.log() statements printing that the given functionality is being implemented.

That's it!

In the code below, we extend the Shape() constructor defined in the previous chapter by augmenting its prototype:

function Shape(x, y, fill = '#000') {
    this.x = x;
    this.y = y;
    this.fill = fill;
}

Shape.prototype.move = function(x, y) {
    console.log('Moving the shape to (${x}, ${x}).');
}

Shape.prototype.delete = function(x, y) {
    console.log('Deleting the shape.');
}

With Shape defined fully, it's time to consider the Rect class. The Rect class could define a draw() method to draw a rectangle shape on the canvas. Extending the Rect constructor from the previous chapter, here's how Rect() would look, including Rect.prototype.

function Rect(width, height, x, y, fill) {
    // initialise this Shape
    Shape.call(this, x, y, fill);

    this.width = width;
    this.height = height;
}

Rect.prototype.draw = function() {
    console.log('Drawing the rectangle.');
}

Recall the purpose of the statement Shape.call(this, x, y, fill) here in line 3.

It effectively gets a Rect instance to have all the traits of a Shape instance by calling the Shape() constructor with the respective args. This reduces the need to repeat the code of Shape() inside Rect() — we simply reuse the Shape() constructor.

Part of the inheritance is done, i.e. the properties (characteristics) have been initialised — now we're only left with the part of inheriting methods from the Shape class.

How to do that?

Well, if we could somehow configure the prototype of Rect.prototype to inherit from Shape.prototype then we'd be on the right track. Now how to do that?

Hmm. Good question. Let's think on it...

One way is kind of a clever workaround. First, we set Rect.prototype to new Shape() and then define all the instance methods of Rect on Rect.prototype. This has a very obvious consequence: Rect.prototype gets its prototype configured to Shape.prototype.

In the code below, we define the Rect() function as before and then set Rect.prototype to new Shape() in line 9, before defining the draw() method on it:

/* ... Shape definition */

function Rect(width, height, x, y, fill) {
    // initialise this Shape
    Shape.call(this, x, y, fill);

    this.width = width;
    this.height = height;
}

Rect.prototype = new Shape(); Rect.prototype.draw = function() { console.log('Drawing the rectangle.'); }

Keep in mind that the Shape instance assigned to Rect.prototype here is only meant to extend the prototype chain of a Rect instance to include the Shape.prototype object, after the Rect.prototype object.

It isn't meant to be used as an instance — that explains why we don't pass in arguments to new Shape().

That is just it!

Now, as it clearly seems, it's quite vague to call new Shape() and assign it to Rect.prototype. At least in this case, it was possible to leave out the args to the constructor Shape(), but if it wasn't possible then we'd have to manually pass given arguments.

Frankly speaking, it's a loose practice to extend the prototype chain of an instance in this way. Ideally, constructor calls shall only be used to create actual instances, not to create some dummy instances for the purpose of being assigned to F.prototype for a given function F.

Even programatically speaking, calling new Shape() on Rect.prototype creates redundant properties x, y and fill on Rect.prototype that won't ever be used.

A much better way, both technically and in terms of code readability is to use the Object.create() method.

Let's configure the prototype of Rect.prototype without using new Shape().

The way to do this is... You should think on it first. It's really easy, believe it.

Alright, so assuming you've done your thought work, let's see the Object.create() way to implement inheritance of a prototype itself.

Recall that Object.create() creates a new object whose prototype is set to the first arg passed to the method. In our case, we need to set the prototype of the object Rect.prototype to Shape.prototype.

So what we need to do is simply call Object.create() passing it Shape.prototype as an argument and then assign the resulting object to Rect.prototype.

Voila!

This would have two consequences:

  1. Rect.prototype would be an empty object since we haven't passed any initialisation properties via the second arg to Object.create().
  2. Secondly, Shape.prototype would becomes the prototype of Rect.prototype. That is anything defined on Shape.prototype would be accessible on Rect.prototype and ultimately on all Rect instances.

Perfect!

In the code below, we implement this simple Object.create() trick and then go on with our usual Rect's instance method definitions.

/* ... Shape definition */

function Rect(width, height, x, y, fill) {
    // initialise this Shape
    Shape.call(this, x, y, fill);

    this.width = width;
    this.height = height;
}

Rect.prototype = Object.create(Shape.prototype); Rect.prototype.draw = function() { console.log('Drawing the rectangle.'); }

Now, let's test everything as before:

var r1 = new Rect(20, 50, 0, 0);
undefined
r1.draw()
Drawing the rectangle.
undefined
r1.move(-1, 5)
Moving shape to (-1, 5).
undefined
r1.delete()
Deleting the shape.
undefined

Great! The code works just as expected.

Moreover, the best part is that now there are no redundant properties on Rect.prototype as there were before (when using new Shape()).

Object.create() is one of the beauties of JavaScript. What's even more beautiful is that it could be implemented purely on the idea of a constructor and its prototype property. More on this later in an upcoming exercise in this unit.

What's the prototype chain of the r1 object above.

  • Rect.prototype, Shape.prototype
  • Rect.prototype, Shape.prototype, Object.prototype
  • Rect, Rect.prototype, Shape.prototype
  • Rect, Rect.prototype, Shape.prototype, Object.prototype

Retrieving the prototype

Up until now, we've seen numerous concepts revolving around the quite simple idea of prototypes. We've seen how to create an object with a given prototype; how to define stuff on a constructor's prototype property that would ultimately be reused by all of its instances; and finally how to implement prototypal inheritance.

However, still a very basic question is unaddressed.

That is, given any object, how do we retrieve its prototype?

Well, if the object is an instance of a constructor F, then the prototype of that object is simply equal to F.prototype.

But if we don't know about the constructor of an object in the first place, this would be a problem. Well, retrieving the constructor of an instance is quite easy — just use the constructor property.

But what if the constructor property is not available on the instance?

In that case, clearly we won't be able to retrieve the constructor of that object and consequently its prototype property.

Even if all these things went right, it might be the case that the prototype of an object is different from the prototype property of its constructor. We'll see how could this be possible.

Furthermore, in some cases it might be completely impossible to retrieve the prototype of an object manually.

To boil this long discussion down, manually figuring out the prototype of an object is not reliable at all — it could give unexpected results, or in some cases no result at all!

So it turns out that a long time ago, JavaScript engine developers realized that retrieving the prototype of a given object is not a very uncommon thing to desire in an application and thus came up with a non-standard way to retrieve the prototype of an object — the __proto__ property.

For a given object o, its __proto__ property simply returns a reference to the prototype of o.
The __proto__ property is an accessor property defined on Object.prototype. In this way, it's available on almost all objects in JavaScript.

Let's inspect __proto__ on a couple of objects in JavaScript.

For the sake of clarity, we've not directly logged the __proto__ objects of given values below — rather we've compared them against a given prototype object to showcase the return value of __proto__ in each case.

[1, 2, 3].__proto__ === Array.prototype
true
{ x: 0 }.__proto__ === Object.prototype
true
10 .__proto__ === Number.prototype
true
'10'.__proto__ === String.prototype
true
var a = {}
undefined
Object.create(a).__proto__ === a
true
function F() {}
undefined
F.__proto__ === F.prototype
false

The last log here is particularly important to be aware of. For a given function, its __proto__ property and prototype property don't hold the same objects.

For a function F, F.__proto__ holds the prototype of the function object F which turns out to be Function.prototype, whereas F.prototype holds the prototype of all instances of F().

Now, due to a high adoptage of this non-standard __proto__ property, it soon found its way into the ECMAScript standard, however purely as a legacy feature given for backwards-compatability.

In place of __proto__, a much cleaner and sophisticated utility was drafted: the static Object.getPrototypeOf() method.

As the name suggests,

For a given object o, Object.getPrototypeOf(o) simply returns a reference to the prototype of o.

Here's its syntax:

Object.getPrototypeOf(obj)

The one and only obj argument specifies the object whose prototype ought to be retrieved. The method returns back the prototype of obj.

As with __proto__, let's inspect this method on a bunch of values:

Object.getPrototypeOf([1, 2, 3]) === Array.prototype
true
Object.getPrototypeOf({ x: 0 }) === Object.prototype
true
Object.getPrototypeOf(10) === Number.prototype
true
Object.getPrototypeOf('10') === String.prototype
true
var a = {}
undefined
Object.getPrototypeOf(Object.create(a)) === a
true
function F() {}
undefined
Object.getPrototypeOf(F) === F.prototype
false

If you are developing JavaScript applications and ever want to retrieve the prototype of a given object, you MUST use this standard Object.getPrototypeOf() method.

Although __proto__ is supported on major browsers, it's always recommended to avoid using non-standard features as much as possible, even if there is practically no difference between the standard and the non-standard features, as is the case with __proto__ and Object.getPrototypeOf().

You can read more about __proto__ at MDN's official documentation for __proto__.

Setting an object's prototype

As we've seen above, it's quite trivial to spin up a new object in JavaScript that has a given prototype.

For example, in the case of a constructor function, we could instantiate an object out of it, set the prototype of the constructor to an object p and thus get all instances of the constructor to inherit from p.

On the otherhand, Object.create() could be used to create a new object with a given prototype, i.e. by calling Object.create(p), without having to manually go through the process of constructor function creation and then instantiation.

All good.

But what if we have an existing object and want to change its prototype to some other object.

Uptil now, we've not seen any way to do so.

However, there is a way. In fact, there are two ways to accomplish this:

  1. Assign a value to the object's __proto__ property.
  2. Call the Object.setPrototypeOf() method.

Assigning a value to the __proto__ property is just how we'd assign a value to any other property in JavaScript, i.e. obj.__proto__ = value.

On the otherhand, the static method Object.setPrototypeOf() takes two arguments and makes the second one the prototype of the first one.

Syntactically it looks like this:

Object.setPrototypeOf(obj, proto)

proto is made the prototype of the object obj. The return value of this method is obj.

Simple!

Let's see both of these utilities in action:

Here's our old example with the two objects a and b:

var a = { x: 10, y: 20 };
var b = { p: 100, q: 200 };

We'll make a the prototype of b:

First, let's do this using __proto__:

var a = { x: 10, y: 20 };
var b = { p: 100, q: 200 };

b.__proto__ = a; console.log('b.x:', b.x); console.log('b.y:', b.y); console.log('b.p:', b.p); console.log('b.q:', b.q);
b.x: 10 b.y: 20 b.p: 100 b.q: 200

Now, using the Object.setPrototypeOf() method:

var a = { x: 10, y: 20 };
var b = { p: 100, q: 200 };

Object.setPrototypeOf(b, a); console.log('b.x:', b.x); console.log('b.y:', b.y); console.log('b.p:', b.p); console.log('b.q:', b.q);
b.x: 10 b.y: 20 b.p: 100 b.q: 200

Easy, isn't this?

Now you might be thinking that Object.setPrototypeOf() is much better than using Object.create() because it allows us to configure the prototype of an existing object and thus prevent having to write each of the properties one-by-one.

It clearly seems this way.

The problem is that the language discourages doing so.

If you headover to MDN's official documentation on Object.setPrototypeOf(), or even the documentation on __proto__, you'll see warning signs here and there asking you to refrain from using them.

Object.setPrototypeOf() and __proto__ both have a negative impact on performance in the long term.

They disrupt inline caches maintained for fast object property access internally in the engine, as well as a couple of other optimizations, discussing which are out of the scope of this chapter.

To read more about the internals of V8, the JavaScript engine used in Google Chrome, when accessing and resolving object properties head over to JavaScript engine fundamentals: optimizing prototypes.

Long story short, there are potential performance concerns using it. Note that it's not to say that it's fatal t use Object.setPrototypeOf() but rather only that it should be avoided as much as desired.

The best way is to use Object.create() since it doesn't modify an existing object but rather introduces a new object into the code with a given prototype. This doesn't disrupt given optimizations made by the engine.

Remember to always try your level best to avoid assigning a value to the [[Prototype]] of an existing object. It might have far-flung effects on the performance of your application.

"I created Codeguage to save you from falling into the same learning conundrums that I fell into."

— Bilal Adnan, Founder of Codeguage