Why JavaScript is a Prototype-based OOP
Tags: javascript, webdev, beginners, oop
Published: 2023-03-30 20:11:09

In object-oriented programming, we can distinguish between two types of languages. Class-based and prototype-based languages.

Class-based languages are centered around classes as the blueprint for creating objects. However, in prototype-based language classes are explicitly excluded, and objects inherit from other objects using prototypes.

Compared to class-based languages like C++ and Java, JavaScript is considered a Prototype-based object-oriented programming language.

This article delves deep into understanding prototype-based object-oriented programming in JavaScript.

By the end of this article you should be able to know:

* The differences between class-based and prototype-based OOP
    
* How inheritance works in class-based programming
    
* How inheritance works in prototype-based programming
    
* Prototypes and `__proto__` properties
    
* How to implement prototypal inheritance
    

Let's get started

## Introduction

Whiles working at Netscape, Brendan Eich developed JavaScript as a scripting language to be used in Netscape Navigator, the company's flagship web browser.

Netscape had initially partnered with Sun to incorporate Java programming language into the Navigator. However, the language had some complexities (for instance the JVM consumes a lot of resources, it took several seconds to start a Java applet, etc) that would not appeal to scripters who need to add interactivity to web pages.

To rectify this, Brendan Eich developed JavaScript as a utility language targeted toward scripters and designers.

Netscape's management instructed Brendan Eich not to include advanced features such as classes and modules in JavaScript, to prevent it from appearing to compete with Java.

Because Brendan was not allowed to include classes (which provides a convenient approach for creating objects and inheriting properties and methods), he had to find a way to still maintain the Object-oriented model in JavaScript. He opted for prototypes and implemented prototypal inheritance instead.

Javascript didn't adopt the object-oriented model used by C++ or Java when it was designed because the creator had no time to copy any classical OO model, and Sun didn't want classes included in JS, since JS was supposed to be just a 'sidekick' to Java.

JavaScript is therefore a prototype-based, object-oriented language and uses prototypal inheritance instead of classical inheritance.

**Simply put, JavaScript does not have classes, it has prototype objects cloned to produce new objects. Classes are only syntactic sugar for prototypes.**

## Class-based Programming language

In Class-based programming, objects are built based on the classes. The properties and behavior of an object are defined by a `class` that serves as a blueprint to create concrete objects.

Consider this analogy, if you were to develop a mobile phone device, you would first design a blueprint that contains all the structure and behavior needed to build the mobile phone. For instance the exterior, operating system, circuit boards, etc, and then build the phone based on that blueprint.

This blueprint is referred to as a `class` . It is an expandable program code template for creating objects. An `object` is a real-world entity (for instance a mobile phone).

The blueprint (`class`) can be extended to build other variations of mobile phone devices ( basic phones, feature phones, and smartphones)

**Simply put, in class-based programming, an object must be explicitly created based on a class.**

## Prototype-based Programming language

Prototype-based programming is a style of object-oriented programming in which **classes are not explicitly defined**. Inheritance is performed by reusing existing objects that serve as prototypes (objects inherit from other objects through a **prototype** property).

**It permits the creation of an object without first defining its class.**

Consider the same analogy of developing a mobile phone device in prototype-based programming.

You first begin by creating the objects ( no blueprints or classes). You assemble the exterior, operating system, circuit boards, etc, and spin up a mobile phone. We can then clone the initial mobile phone and then extend the structure and behavior for the required mobile device (for instance, a smartphone with a wider screen size, touch functionality, sensors, etc).

Using this approach, each mobile phone would be cloned from the generic mobile phone object.

**In the world of prototype-based OOP, you build an object and swiftly create "clones" of it compared to the class-based approach, which requires a class to create an object, and then extend the child class to inherit properties and methods from the parent.**

## Understanding the concept of Prototype-based OOP

In class-based OOP, a `class` serves as a blueprint for creating objects. A `child class` will inherit the properties and methods defined in the `parent class` , and distinct `objects` are created using the `constructor` function.

However, in prototype-based OOP, we do not need to define a `class` to enable us to create `object`. Objects are created directly.

**Because we don't define classes, we need an approach that will enable other objects to inherit properties and methods from the initial object.**

There is a hidden property in **every object** called **prototype** that enables us to achieve that.

Let's explore this further in the next section.

## What is a Prototype?

A prototype is a built-in (hidden) property represented by `[[Prototype]]` that points to another object. The value pointed at by the `[[Prototype]]` is casually known as "the prototype of that object"

Consider the example below:

```javascript
//user object
const user = {
    name: "Emmanuel",
    age: 23,
    city: "Accra"
}

console.log(user)
```

In the console, you can view the properties of `user`, alongside the `[[Prototype]]` (hidden property).


![Javascript proto](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/539ge6a9nuwfcrjnn898.png)

Because the value of the `[[Prototype]]` is an `Object`, we say, it is the **prototype of the** `user` **object**. The `Object` will also have a prototype property (represented as `__proto__` ) including other built-in methods.

This `__proto__` is not the same as the hidden `[[Prototype]]`. It allows us to read and assign details to the `[[Prototype]]`

Let's expand the `Object` to investigate


![JS Prototype](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wxu8gzj2qyex7fvzipey.png)

### Prototype chain

Whenever the `__proto__` property points to an `object` . That object will also have a prototype that will also point to another object. In effect, it creates a **prototype chain.** The prototype chain ends with an object that has a value of `null`


![Javascript prototype](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/70jo94bl0okbd4w1xkpg.png)

## How prototype works

Consider the `user` object below.

It has three properties: `name`, `age` and `city`.

```javascript
const user = {
    name: "Emmanuel",
    age: 23,
    city: "Accra"
}
```

We can access these properties, via the dot (`obj.propName` ) or bracket (`obj['propName'])` .

Let's access the `name` property

```javascript
user.name
// which returns 
Emmanuel
```

We instantly have access to the value(`Emmanuel`)

**Now, what happens if we access a property that does not exist in an object?**

If we access a property and the object does not directly have that property, the JS engine will look for a property with that name by first searching the `[[Prototype]]`, and because it references an object, **it looks for the property in that object.**

If it cannot locate the property, that object `[[prototype]]` will be searched. This search will continue in turns until it a match is found, or reaches the end of the prototype chain.

At the top of the prototype chain is `null`, at this stage, the property was not found, and `undefined` is returned.


![Prototype chain](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1izmm3jt4agxk5jqz43k.jpg)

The code below illustrates the prototype chain

```javascript
let person  = {
  eats: true,
  hasLegs: 2,
  walks(){ console.log('I can walk')}
}
//define another object
let man = {
  hasBreast: false,
  hasBeard : true,
  
}
//set the prototype of man to person object
man.__proto__ = person;
//define a third object
let samuel = {
   age: 23
}
//set the prototype of samuel to man
samuel.__proto__ = man;
//access walk method from samuel
console.log(samuel.walks())
//access hasBeard from samuel
console.log(samuel.hasBeard)
```

* We define a `person` object with `eats` and `hasLegs` properties, including a `walks` method
    
* We create a `man` object and set the prototype of man to the `person` object using `man.__proto__= person`
    
* We create a specific man `samuel` and set the prototype of `samuel` to `man` using `samuel.__proto__ = man`
    
* Now, we try accessing the `samuel.walks()` and `samuel.hasBeard` It is clear from the `samuel` object that there is no `walk` method and a `hasBeard` property.
    

How then, do we get the output `I can walk` and `true` ?

* Whenever `samuel.walks()` is called, the JavaScript engine will first search the object `samuel` for the method.
    
* If it is not found, the `[[Prototype]]` of `samuel` will be searched.
    
* The `[[Prototype]]` has been set to the object `man` , hence the JavaScript engine checks the `man` for the `walk` method.
    
* If it is not found, the `[[Prototype]]` of `man` will be searched.
    
* Its `[[Prototype]]` has been set to the `person` , so we check the `person` for the `walk` method.
    
* Finally, at the top of the prototype chain, we can locate the method `walk` in the object `person` and the JavaScript calls the method even though it wasn't defined in the object `samuel`.
    

![JavaScript prototype](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9sd0mnhhdi6e6aro73dm.png)

Let's consider another example. Supposing we want to convert `user.name` to upper case, we can do it as below:

```javascript
//convert from Emmanuel to EMMANUEL
const user = {
    name: "Emmanuel",
    age: 23,
    city: "Accra"
}

console.log(user.name.toUpperCase())
```

When we call the method `toUppercase()`

* The JavaScript engine looks for the `toUpperCase` in the `user` object
    
* If it can't locate it there, it searches the `[[prototype]]` property of `user` for `toUpperCase`
    
* Finds it there, and executes the method.
    


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

### Dimming Properties

Whenever you define a property in an object, and that property has the same name as a property in the `[[prototype]]`, the object's prototype is dimmed and that of the defined property takes precedence.

Consider this example

```javascript
const myDate = new Date(1999,05,26)
console.log(myDate.getFullYear()) // 1999
//define a method for myDate
myDate.getFullYear = function(){
    console.log('changed the default getFullYear method')
}
myDate.getFullYear()
```

* `getFullYear()` is a built-in method on the `myDate` object. When executed, it returns the full year
    
* We assign a property with the **same name** to the `myDate` object, the value of the property is a function that consoles `changed the default getFullYear method`
    
* This approach overwrites the built-in method, this is because the JS engines first check the `myDate` object for the `getFullYear` property. Since it finds it there, there is no need to check the object's prototype
    

This is called "shadowing" the property

## Setting the prototype on an object

There two main approaches in setting an object's prototype are:

* Object.create()
    
* Constructor
    

Let's explore this further.

### Using `Object.create()` to set the prototype

The `Object.create()` creates a new object and allows you to use existing objects as the new object's prototype.

The syntax is as below:

```javascript
Object.create(proto) // proto is the existing object
```

See the example below:

```javascript
const user = {
    isLoggedIn: false,
    greetUser(){
        console.log(`Howdy ${this.name} !`)
    }
}
//create a new object and set the prototype
const admin = Object.create(user)
```

* We defined a `user` object, with `isLoggedIn` property and `greetUser` method.
    
* The `Object.create()` creates a new `admin` object.
    
* We set the prototype of the `admin` object to the `user` using the `Object.create(user)`
    

Below is the result of logging the `admin` to the console


![JS Prototype](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/72muhfqo96au6mtwnei4.png)

Let's examine the code above:

* When we first investigate the details of the `admin` object, it looks empty. However, we notice there exists a `[[Prototype]]` property. This property is in-built and references the prototype of the `admin` object.
    
* We conclude that the prototype has been set to the existing `user` object.
    

We can also assign properties to the `admin` object. See the example below:

```javascript
const user = {
  isLoggedIn: false,
    greetUser(){
        console.log(`Howdy ${this.name} !`)
    }  
}

//create an object an set the prototype
const admin = Object.create(user)
console.log(admin)
//assign name property to the admin object
admin.name = "Emmanuel"
```

The `admin` now has `name` property assigned to it. This `name` property is set on `admin` but **not** on `user`.

Now that we've set the prototype of the object, let's try accessing the `greetUser()` that was defined in the `user` object from the `admin`.

```javascript
const user = {
  isLoggedIn: false,
    greetUser(){
        console.log(`Howdy ${this.name} !`)
    }  
}

//create an object an set the prototype
const admin = Object.create(user)
console.log(admin)
//assign name property to the admin object
admin.name = "Emmanuel"
//access greetUser from admin 
admin.greetUser()
// output
Howdy Emmanuel !
```

The output is as below:


![JS Prototype](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/16j89d4gey2t1xsmyoa4.png)

**How was it possible to access, the** `greetUser` **method when it was not defined in the** `admn` **object?**

Let's examine this further

* `name` is the only visible property in the `admin` object
    
* There is also a hidden `[[Prototype]]` property, that reference an `Object`
    
* That `Object` is the existing `user` we passed to the `Object.create()` method.
    
* As explained, when we access a property on an object, and that property does not exist, **we will look at the prototype of the object** for the `property`.
    
* In this scenario, the prototype of the object `admin` has been set to `user`.
    
* In the `user` prototype, we have access to the `greetUser` method
    
* Now we can call `greetUser()` on the `admin`, and the prototype will handle the implementation.
    
* This explains why, the `admin.greetUser()` executes the method even though it was not defined in the `admin` .
    
* Note that, the `this` keyword used in the `user` will reference the newly created object ( in this example `admin`). Hence, `this.name` references `Emmanuel`
    

### Using the constructor function to set the prototype

In JavaScript, every function has a `prototype` property. The prototype enables us to add properties and methods to a constructor function.

Whenever we create an object from the constructor function, the object can inherit the properties and methods from the function's prototype.

Here is an example

```javascript
//constructor function
function User (name) {
  this.name =name,
  this.age = 34
}

//add greet method to the function's prototype
User.prototype.greet = function(){console.log(`Howdy ${this.name}`)}
//create a new object
const admin = new User("Jonas");
//access the greet method from the admin
console.log(admin.greet()) // Howdy Jonas
```

* We define a constructor function `User`, with `name` and `age` properties
    
* The `User` has a `prototype` property that allows us to assign the `greet` method.
    
* We created an `admin` object from the `User`
    
* Now, even though `greet` has not been defined in the `admin`, it inherits that method from the prototype.
    
* This explains why we can call the `greet` method on the `admin` object.
    

New objects created from the constructor function will also inherit the `greet` method as well as additional properties and methods assigned to the prototype.

Furthermore, if a prototype value is changed, all the new objects will have the updated value.

See the example below:

```javascript
function User (name) {
  this.name =name,
  this.age = 34
}
//create a new object
const admin = new User("Jonas");

//add greet method to the constructor function 
User.prototype.greet = function(){console.log(`Howdy ${this.name}`)}

//in effect extending the object
console.log(admin.greet())

//add additional method to the prototype 
User.prototype.userAction = function(){console.log(`${this.name} what do you like to learn today`)}

//access the new method  (*)
const user2 = new User('Clement')
user2.userAction() 
//output
Clement what do you like to learn today
//change the prototype property
User.prototype.greet = function(){console.log(`Hi ${this.name}`)}

//verify the update method
user2.greet() // Hi Clement
```

### Understanding the `__proto__`

We can access the prototype of an object using the `obj.__proto__` syntax.

`__proto__` is the internal property of an object, pointing to its prototype.

In the example below, we read the prototype of the object `user2`

```javascript
console.log(user2.__proto__)
```


![JS Prototype](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8a6n9d9yr94bc1d28svj.png)

Reading the prototype with `__proto__` is considered outdated and has been deprecated. The current approach is to use the `Object.getPrototypeOf(obj)`

```javascript
Object.getPrototypeOf(user2)
```

We can also set the prototype of an object using the `__proto__` .

Take a look at the example below:

```javascript
const obj = {
  greet: function(){console.log('How are you today')}
}

const obj2 = {
  
}
//set the prototype of obj2
obj2.__proto__ = obj;

//access the greet method
console.log(obj2.greet())
```

* We define an `obj` with a `greet` method
    
* We define `obj2` with is an empty object literal
    
* We access the `__proto__` of `obj2` and assign the details of `obj` . This will copy all the properties and methods in `obj` to `obj2`
    
* Henceforth, we can call the `greet` method on `obj2` even though it was not defined there
    
* `obj2` has inherited the `greet` method from `obj`
    

**Using** `__proto__` **is the same thing as using the** `extends` **keyword in OOP languages.**

The current approach to setting the prototype of an object is to use the `Object.setPrototypeOf(obj, proto)` . This sets the `[[Prototype]]` of the `obj` to what we define in the `proto` argument.

The example below changes the prototype of the `user2` object

```javascript
//using user2 object created earlier
Object.setPrototypeOf(user2, {changeProto: function(){console.log('changing the prototype')}}); // change the prototype of user2
```

* We have changed the prototype of `user2` from `greet` method to `changeProto` method
    
* We can verify the change by reading the prototype using the `Object.getPrototypeOf(user2)`
    

The output of the above is as below


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

## Importance of prototypes in OOP

A prototype is a flawless approach to defining the OOP model in JavaScript, `classes` are only syntactic sugar for prototypes.

Whenever we define a `class`, it is transpiled to a constructor function with an in-built prototype property

Below is an illustration

```javascript
class User {
 greetUser(){
         console.log('Hello world')
 }
}
//transpiled to 
function User {
  User.prototype.greetUser = function(){ console.log('Hello world')}
}
```

## Prototypal Inheritance

In programming, inheritance occurs when one object is able to access all the properties and methods in another object.

Unlike other languages like C++ and Java which implements classical inheritance, JavaScript implements Prototypal inheritance.

With classical inheritance, the child class extends the parent class to enable it to inherit the properties and methods defined in the parent class. A definite `object` can then be built from the instance of the class.

However, we don't need to define `class` when dealing with prototypal inheritance. We define a `object` with its properties and methods, access the initial object, and extend it using the prototype. This new object will then inherit all the properties and methods defined in the initial object.

**Prototypal inheritance is a mechanism involving objects inheriting from any other objects rather than from classes.**

Everything we discussed previously made use of the concept of prototypal inheritance. For instance, we had defined an object `user` with its properties and methods, then new objects we create will inherit the properties and methods defined in the `user` object

## Why are there so many ways to manage Prototype

There are different approaches to managing `[[Prototype]]` and most often it becomes confusing. How did that happen and why?

The JavaScript language has had prototypal inheritance included in its since its inception. However, ways to manage it have evolved.

* The `prototype` property of a constructor function has been the oldest way to create objects with a given prototype.
    
* Late 2012, `Object.create` provided the ability to create objects with a given prototype, however, it lacked the ability to get or set the prototype. To give more flexibility to developers, browsers implemented the `__proto__` accessor allowing the user to get or set a prototype.
    
* `Object.setPrototypeOf` and `Object.getPrototypeOf` were added to the standard in 2015, to handle the same functionality as `__proto__`. As `__proto__` was the de-factor, it was deprecated and pushed to Annex B of the standard, that is: optional for non-browser environments
    
* In 2022. it was officially allowed to use `__proto__` in object literals `{...}` but not as a getter/setter (still in Annex B).
    

## Summary

* In Class-based programming, objects are built based on classes.
    
* Prototype-based languages permit the creation of an object without first defining its class.
    
* There is a hidden property in every object called **prototype** that enables us to inherit properties and methods
    
* The value pointed at by the `[[Prototype]]` is casually known as "the prototype of that object"
    
* Prototypal inheritance is a mechanism involving objects inheriting from any other objects rather than from classes.
    

<sup>If you have found value in this article, please comment or share it on your social handles. It will be of help to somebody. Follow me on </sup> [<sup>https://twitter.com/emmanuelfkumah</sup>](https://twitter.com/emmanuelfkumah) <sup> for dev tips.</sup>