✅ JavaScript Inheritance without classes
Tags: javascript, proto, webdev, beginners
Published: 2023-07-09 10:54:06

> In previous tutorial I mentioned the [[Prototype]] chain several times, but haven’t said what exactly it is. We will now examine prototypes in detail. 
> Before starting with this tutorial please do not have any preconceived ideas about any topic as the keywords might be similar to other languages but their meaning might be completely different in JavaScript.

## Table Of Contents
<a href='#thisid1'>1. What is Prototype? </a>
<a href='#thisid2'>2. [[Prototype]] links </a>
<a href='#thisid3'>3. __proto__ </a>
<a href='#thisid4'>4. '.constructor' Property </a>
<a href='#thisid5'>5. Getters and Setters</a>
<a href='#thisid6'>6. [[GET]] Operation</a>
<a href='#thisid7'>7. [[PUT]] Operation</a>



---

<h2 id='thisid1'>1. <u>What is Prototype?</u></h2>
_Prototype is a mechanism by which JavaScript objects inherit features from one another._ 

But when it comes to inheritance JavaScript unlike other Object-oriented languages like C++ or Java doesn't have classes, it only has objects. So, unlike other languages JavaScript uses objects for inheritance.

At this point you might point out that ES6 introduced Class into JavaScript, but that is just a syntatic sugar provided for ease of use. JavaScript do not have any concept of Class just introducing a keyword doesn't change that. Under the hood it is all just objects and constructor functions.

---

<h2 id='thisid2'>2. <u>[[Prototype]] links</u></h2>
Objects inherit features from another objects but how do they access these features ? 
The answer is **[[Prototype]]** - _it is a hidden private property of objects which references other objects. An object's prototype is the object which it descends from or inherits from._

There are generally two ways of creating [[Prototypes]] links 
1. Object.create()
2. new Operator

### 2.1 Object.create()
Object.create() takes objects as argument and returns another object which is [[Protype]] linked to the former object.

```js
var obj1 = {
    a : 5,
    name : 'obj1'
};

var obj2 = Object.create(obj1);
obj2.name = 'obj2';

console.log(obj2.a); // 5
console.log(obj2); // { name : 'obj2' } -> doesn't have 'a' property
```
In the above example, the `obj2` was able to access property `a` even though it does not own the property. This is because `obj2` is [[Prototype]] linked to `obj1`.

Let us now see what the last line prints in the console. If you look closely you will see it has a dropdown arrow besides it. Using it we will inspect the `obj2` object.

![Inspect the object](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gmwisukt8sppi7av7y4x.png)

In the above image you can see [[Prototype]] linkage of `obj2`. Also notice that the `obj1` object is [[Prototype]] which points at the native Object() contructor. It contains all the default function provided to objects which can be accessed via the prototypal inheritance.
**Can we create objects which are not linked to the native Object() contructor?**
The answer is **'YES'** by passing 'null' to Object.create(). This object is usually called dictionary. Below I have just written JavaScript directly in my browser console. `Yes, you can do that!.`

![Dictionary object](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5k215o4r73z1jho0hyse.png) 

### 2.2 new Operator
Every function in JavaScript has data property called `prototype`. When function is called with `new` operator this `prototype` is set as the prototype of the newly created object. Let us demonstrate the working with an example :- 

```js
function fun(){
    this.a = 4;
}

var obj = new fun();

console.log(obj);
console.log(fun.prototype);
```

![Displaying prototype](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rbs23kqagcb0fmskhbou.png)

Here you can see the `fun.prototype` is same as [[Prototype]] of `obj`.

---
<h2 id='thisid3'>3. __proto__ </h2>

It is commonly called `dunder proto` or `double under proto`. It is a property of Object.prototype which exposes the hidden [[Prototype]] property of an object. It can be used to modify object's [[Prototype]] link.

```js
var obj1 = {
    name : 'obj1'
};

var obj2 = Object.create(obj1);
obj2.name = 'obj2';

console.log(obj2.__proto__===obj1); // true
console.log(obj2.__proto__===Object.prototype); // true
```

Since, we can manually change the [[Prototype]] links using the **\_\_proto\_\_** property, care must be taken so that no cycles are formed.

The use **\_\_proto\_\_** property has now depreciated and these properties are used instead :-

```js
var obj1 = {
    name : 'obj1'
};
var obj2 = {
    name : 'obj2'
}

// earlier obj1.__proto__ = obj2
Object.setPrototypeOf(obj1,obj2); 

// earlier obj1.__proto__
console.log( Object.getPrototypeOf(obj1) ); // { name : 'obj2' }
```

---
<h2 id='thisid4'>4. <u>'.constructor' Property</u></h2>

Just the name is enough to confuse people, because there are no constructors in JavaScript. In fact there are no classes in JavaScript, so need of the constructor. It can be pretty misleading for example consider the following code : 

```js
function fun(){
    this.a = 5;
};

var obj = new fun();

console.log( obj ) // { a : 5 }
console.log(obj.constructor);
// ƒ fun(){
//     this.a = 5;
// }
```
It seems that the `obj` was constructed with the help of function `fun` so it has a property `constructor` stating that it was constructed by `fun`.But if you look closely `obj` doesn't have `constructor` property. 
**So, where did it come from?**
The answer is `fun.prototype`, if we inspect the function `fun.prototype` we would find that it has a property `constructor`. The object `obj` was only able to access it because it was [[Prototype]] linked to `fun.prototype`.

```js
function fun(){
    this.a = 5;
};

var obj = new fun();

console.log(obj.hasOwnProperty('constructor')); // false
console.log(fun.prototype.hasOwnProperty('constructor')); //true
```

So, what is the problem can't we still find that `obj` was constructed using the `fun` function? Yes, that is only true for the mean time until anyone changes [[Prototype]] link, then everything falls apart. 

```js
function fun1(){}
function fun2(){}
var obj = new fun1();

console.log( obj.constructor ); // fun1

Object.setPrototypeOf(obj1,fun2.prototype);
console.log(obj.constructor); // fun2 -> it got changed
```

Therefore, `obj.constructor` does not point to the function that constructed it. Also remember that the `constructor` is not a property of object but of the function.

```
NOTE :- Even if obj.constructor = fun1, 
it is not safe to assume that obj was constructed by fun1
```

---
<h2 id='thisid5'>5. <u>Getters and Setters</u></h2>

In JavaScript, accessor properties are methods that get or set the value of an object. For that, we use these two keywords:
- **get :** to define a getter method to get the property value
- **set :** to define a setter method to set the property value

The following are two ways of declaring the getters and setters :-

```js
// FIRST METHOD -> OBJECT LITERAL METHOD
var obj1 = {
    name : "Peter Parker",
    get getName(){
        return this.name;
    },
    set changeName(n){
        this.name = n;
    }
};
console.log(obj1.getName()); 

// SECOND METHOD -> Object.defineProperty();
var obj2 = { name : 'Bruce Wayne' };
Object.defineProperties(obj2,'getName',{
    get : function(){
        return this.name;
    }
});

Object.defineProperty(obj2,'changeName',{
    set : function(n){
        this.name = n
    }
})
console.log(obj2.getName());
```

---

<h2 id='thisid6'>6. <u>[[GET]] Operation </u></h2>

When we try to access properties on any object then [[GET]] operation is performed to retrieve the value. When we access the property on object, it firsts checks if the object contains the property or not. If it contains the property then it simply returns the value. If the requested property is not found in the object itself, JavaScript will traverse up the prototype chain until it finds the property or returns undefined if it doesn't exist.

**So, where do you think this chain ends?**
JavaScript traverses the [[Prototype]] chain until the [[Prototype]] of certain object in chain points at `null`. For the most cases the last object is `Object.prototype` but if object is created using `Object.create(null)` then it's [[Prototype]] points at `null`.

```js
var obj1 = {
    a : 4
};

var obj2 = Object.create(obj1);
var obj3 = Object.create(obj2);

console.log(obj3.a); // 4 
// obj3 -> obj2 -> obj1 ( property found returns value )

console.log(obj3.b) // undefined
// obj3 -> obj2 -> obj1 -> Object.prototype -> null 
// ( property not found returns undefined )
```

---
<h2 id='thisid7'>7. <u>[[PUT]] Operation </u></h2>

[[GET]] operation was easy right, well [[PUT]] operation is where things get really interesting. [[PUT]] operation is performed when we JavaScript encounters assignment to a object property. For eg:- `obj.a = 5`.

There arises various scenarios :- 

```
1. The object already has the property.

2. The object doesn't have the property but 
 some object in [[Prototype]] chain has the property 
   a. The property is writable false 
   b. The property is writable true
   c. If the setter is present

3. Neither the object nor other object in 
 [[Prototype]] link has property. 
```


Let us resolve all these scenarios one by one :- 

### 1. If the object already has the property 
In this case the property would be updated without any further consideration.

```js
var obj1 = {
    name : 'obj1'
};

var obj2 = { name : 'obj2' };
Object.setPrototypeOf(obj1,obj2); // obj2 [[Prototype]] linked to obj1 

obj2.name = 'obj2 changed';

console.log(obj2.name,obj1.name);// 'obj2 changed', 'obj1'
// the name property of obj2 was successfully updated
// without ever changing the value of obj1
```
### 2. The object doesn't have the property but some object in [[Prototype]] chain has the property.
This is a tricky scenario because it there are further 3 possibility :-

#### a. The property is writable false
In this case neither the property would be updated nor new property is added to the object.

```js
var obj1 = {};

Object.defineProperty(obj1,'name',{
    value : 'obj1',
    writable : false
});

var obj2 = Object.create(obj1);
obj2.name = 'obj2';

console.log(obj1.name,obj2.name); // 'obj1', 'obj1`
console.log( obj2.hasOwnProperty('name') ); // 'name' property not added to obj2

// NOTE :- 'name' property was not added to obj1 it 
// was only able to access this property via the [Prototype]] link
// The 'name' property in obj1 remained unchanged
```
#### b. The property is writable true
In this case, property would be added to the current object which would shadow the other object.
Shadowing of property :- When an object has property name same as another object higher up in it's [[Prototype]] chain. 

```js
var obj1 = {
    name : 'obj1' // by default writable true
};

var obj2 = Object.create(obj1);
obj2.name = 'obj2';

console.log(obj1.name,obj2.name); // 'obj1', 'obj2`
console.log( obj2.hasOwnProperty('name') ); // 'name' property added to obj2

// NOTE :- The obj1 object shadows obj2 
// the value of property in obj1 is not changed
```

#### c. Setter is present
In this case, simply the setter is called.

```js
var obj1 = {
    name : 'obj1',
    set changename(n){
        console.log('setter called');
        this.name = n;
    }
};

var obj2 = Object.create(obj1);
obj2.changename = 'obj2'; // setter called

console.log(obj1.name,obj2.name); // obj1, obj2

// NOTE :- Setter is called during the assignment
// the properties in obj1 remains unchanged
```

#### d. Neither the object nor other object in [[Prototype]] link has property. 
In this case, simply the property is added to current object.

```js
var obj1 = {
    a : 4
};

var obj2 = Object.create(obj1);
obj1.b = 5;

console.log( obj1.hasOwnProperty('b') ); // true
console.log( obj1.b,obj2.b ); // undefined, 5

// NOTE :- Property added to obj2
// obj1.b gives undefined as obj1 doesn't have 'b' property
```

---

This post marks the end of this 3 part series where I have tried to explain how objects work in JavaScript. This was a very wonderful experience connecting with new people. 

Also, you can connect with me on [linkedin](https://www.linkedin.com/in/angshu-das-149784210/) and [Github](https://github.com/angDecoder)