DEV Community

Kabir Nazir
Kabir Nazir

Posted on • Edited on

Prototype in Javascript - 02 - The __proto__ property

In our previous article, we looked at a few ways of creating objects. However, we did run into an interesting problem, namely that of unnecessary code reuse. Let us try to understand it better with an example.

    let bird1 = {
      type: 'sparrow',
      canFly: true
    }

    let bird2 = {
      type: 'eagle',
      canFly: true
    }
Enter fullscreen mode Exit fullscreen mode

We have created 2 objects, bird1 and bird2. We can see that while the value of the type property differs, the value of the canFly property remains the same. Rather than have the same property repeated in both objects, wouldn't it be better if we could have a single object called bird, which has a property canFly set to true (if we assume that all birds can fly), and somehow let Javascript know that both the bird1 and bird2 object are going to be inheriting (or copying) the properties of that bird object? In this way, we could have a single bird object in which we could store all the properties that are common in birds and only need to include the unique properties in bird1 and bird2. Something like this

    let bird = {
      canFly: true,
      laysEggs: true,
      hasFourLegs: false 
    }

    let sparrow = {
      color: 'blue'
    }

    let eagle = {
      color: 'brown'
    }

console.log(sparrow.canFly); // Returns undefined now but we ideally want a scenario where it returns true
Enter fullscreen mode Exit fullscreen mode

Javascript allows us to implement the above concept with the special property of an object called [[Prototype]].

[[Prototype]]

In Javascript, objects have an internal property [[Prototype]], which is either another object or null. Although [[Protoype]] is the name given in the ECMAScript specification, for the purposes of this article, we shall be using the term 'prototype'.

The prototype of a Javascript object can be considered as its parent object or its super object. This means that when we try to access a property in an object, and it's missing, Javascript then tries to look for that property in the object's prototype and access it. This is referred to as 'prototypal inheritance'.

Although the prototype is an internal and hidden property of an object, there are other ways to access it. One of them is to use the '__proto__' keyword.

The __proto__ property

Let us see an example of using the __proto__ property for our previous example.

    let bird = {
      canFly: true;
      laysEggs: true;
      hasFourLegs: false 
    }

    let sparrow = {
      color: 'blue'
    }

    let eagle = {
      color: 'brown'
    }

    sparrow.__proto__ = bird;
    eage.__proto__ = bird;

    console.log(sparrow.canFly); // Returns true
Enter fullscreen mode Exit fullscreen mode

In the above code, you can see that we have set the prototype of sparrow as bird using the __proto__ property. Now, when we try to access the canFly property of sparrow, Javascript first looks for it in sparrow. When it doesn't find it there, Javascript then searches for it in its prototype (in this case, bird) and finds it there. Hence, sparrow.canFly is evaluated to true. Similarly, since the prototype of eagle is set to bird too, eagle.canFly also works and evaluates to true.

In the above example, we can say that bird is the prototype of sparrow, or that that sparrow 'prototypically inherits' inherits from 'bird'. The properties of bird, namely canFly, laysEggs and has4Legs, are called as inherited properties.

We can chain prototypes too.

    let object1 = {
      property1: 'exists'
    }

    let object2 = {
      property2: 'exists'
      __proto__: object1
    }

    let object3 = {
      property3: 'exists'
      __proto__: object2
    }

    console.log(object3.property1); // 'exists'
Enter fullscreen mode Exit fullscreen mode

When we look for property1 in object3, Javascript doesn't find it. It then looks for it in its prototype, which is object2. It doesn't find property1 in object2, and further looks for it in object2's prototype (which is object1). It then finds property1 in object1 and returns its value.

Now, you might be wondering, in the above example, what is the value of the prototype of object1? Is it going to be undefined, or is it an empty object? The answer is that it will be null since the prototype is an internal property of every object in Javascript, which can either be another object or null.

In fact, there's a more elegant way of specifying an object's prototype while creating it itself. It's done via the Object.create function.

Object.create

Calling the Object.create function does 3 things:

  1. Create an empty object
  2. Set the prototype of the newly created object as the argument passed in the Object.create() function. This argument is mandatory and can only be either another object or null.
  3. Return the created object.
    let object1 = {
      property1: 'exists'
    }

    let object2 = Object.create(object1);

    console.log(object2.property1); // 'exists'
Enter fullscreen mode Exit fullscreen mode

Hence, as we have seen so far, we can make use of the hidden [[Prototype]] property in Javascript to implement the concept of inheritance and organize our code in a much more efficient and structured manner. In the next article of this series, we shall be discussing the new keyword and how it functions under the hood to create objects in Javascript.

Top comments (2)

Collapse
 
aminnairi profile image
Amin

Hi there, great article and well explained.

Isn't __proto__ obsolete now? I though that Object.setPrototypeOf and Reflect.setPrototypeOf were the successors for that API?

Collapse
 
kabir4691 profile image
Kabir Nazir • Edited

Yes, __proto__ is considered to be obsolete now and instead Object.setPrototypeOf and Object.getPrototypeOf are recommended for a number of reasons. The reasons are explained clearly in javascript.info/prototype-methods.