# Deep Dive into Prototypal Inheritance in JavaScript

> A deep dive into JavaScript's prototypal inheritance — prototype chain, Object.setPrototypeOf, the new keyword, constructor property, and ES6 classes.

By Vishwajeet Raj · 2022-04-24 · https://vishwajeet.co/blog/prototypal-inheritance-javascript

---

## Prototype

Objects in JavaScript have an internal property known as the prototype. It is simply a reference to another object and contains common attributes/properties shared across all instances of the object.

- An object's prototype attribute specifies the object from which it inherits properties.
- The prototype property is non-enumerable, meaning that it doesn't show up when we try to access the object's properties.

## Prototype Chain

When an object gets a request for a property that it does not have, its prototype will be searched for the property, then the prototype's prototype, and so on until an object is reached with `null` as its prototype. **By definition, null has no prototype and acts as the final link in this prototype chain.**

Many objects don't directly have `Object.prototype` as their prototype, but instead have another object that provides a different set of default properties. Functions derive from `Function.prototype`, and arrays derive from `Array.prototype`.

> In a prototypal system, objects inherit from objects.

### Example

```js
const user = {
    firstName: 'Vishwajeet'
}

console.log(user.firstName) // Vishwajeet
console.log(user.lastName) // undefined
console.log(user.toString()) // [object Object]
```

The `toString()` result is not undefined but an actual return value. This is because the `toString()` property lives in `Object.prototype`, which is connected to this object through the prototype chain.

## Setting Prototype

The `Object.setPrototypeOf()` method sets the prototype of a specified object to another object or null.

```js
const entity = {
    isHuman: true
};

const vishwajeet = {
    firstName: 'Vishwajeet',
    lastName: 'Raj'
};

Object.setPrototypeOf(vishwajeet, entity);

console.log(vishwajeet.firstName) // Vishwajeet
console.log(vishwajeet.isHuman) // true
```

> The prototype chain is only searched when the property does not exist on the object.

## for-in loop on Objects with Prototype

If you use a `for..in` loop to iterate over an object, any property that can be reached via its chain and is also enumerable will be enumerated. Use `hasOwnProperty` to count only the object's own properties:

```js
const person = {
    name: 'Vishwajeet',
    lastName: 'Raj'
}

const extraDetails = {
    age: 23,
    eatsApples: true
}

Object.setPrototypeOf(person, extraDetails)

let n = 0;
for (let property in person) {
    if(person.hasOwnProperty(property)) {
        n++;
    }
}
console.log(n)  // 2
```

## Prototype delegation with the new keyword

The `new` keyword does the following things:

1. Creates a blank, plain JavaScript object.
2. Adds a property to the new object (`__proto__`) that links to the constructor function's prototype object.
3. Binds the newly created object instance as the `this` context.
4. Returns `this` if the function doesn't return an object.

```js
function Laptop(maker) {
    this.maker = maker
    this.ram = 4
}

Laptop.prototype.ram = 8
Laptop.prototype.color = 'black'

const myLaptop = new Laptop('Apple')

console.log(myLaptop.ram)   // 4 (found on the instance)
console.log(myLaptop.color) // black (found on prototype)
console.log(myLaptop.__proto__ === Laptop.prototype) // true
```

## What's the difference between `__proto__` and `prototype`?

The difference is that `prototype` is a **property of a class constructor**, while `__proto__` is a **property of a class instance**.

## Understanding Constructor Property

> Every function has the prototype property even if we don't supply it. The default `prototype` is an object with a single property, `constructor`, that points back to the function itself.

```js
function func() {
    console.log('some')
}

console.log(func.prototype.constructor) // [func function itself]

const instance = new func();
console.log(instance.constructor === func) // true
```

The `constructor` property will not always point to the function that created it. We can assign the prototype to a new object:

```js
function func() {
    console.log('some')
}
func.prototype = {}

const instance = new func();
console.log(instance.constructor === func)   // false
console.log(instance.constructor === Object) // true
```

## Prototype Delegation with class Keyword

The `class` keyword was introduced with ES6. It's just syntactic sugar over a regular JavaScript function.

```js
class Human {}
console.log(typeof Human) // function
```

> Classes in JS use prototypal inheritance.

```js
class Human {
    isAlive() {
        return true
    }
}

class Doctor extends Human {
    status() {
        return this.isAlive();
    }
}

console.log(Human.prototype.isAlive()) // true

const doc = new Doctor();
console.log(Object.getPrototypeOf(doc) === Doctor.prototype) // true
console.log(Object.getPrototypeOf(Doctor.prototype) === Human.prototype) // true
```

> The `extends` keyword creates what looks and acts similar to a classical parent-to-child relationship.

With the `extends` keyword, Human's prototype object is linked to Doctor's prototype object. We're able to access the `isAlive` function because it actually lives on Human's prototype object, not on the class itself.
