Understanding prototype in javascript

Vlad O.

Updated:

Prototype is fundamental concepts that every JavaScript developer should understand. In this comprehensive guide, we’ll dive deep into the concept of prototypes, uncover its significance, and explore how it can enhance your JavaScript development journey.

Understanding Prototypes

At its core, JavaScript is a prototype-based language. This means that objects can inherit properties and methods from other objects, known as prototypes. When a property or method is not found on an object itself, JavaScript looks up the prototype chain to find it. This concept of inheritance through prototypes forms the backbone of JavaScript’s object-oriented programming model.

The Prototype Property

In JavaScript, every object has a special property called prototype. This property points to another object, which is used as the source of properties and methods when the object is created through a constructor function or a class. Let’s take a look at an example:

const person = {
    name: 'John',
    age: 30
}
// OR
const person = new Object({
    name: 'John',
    age: 30
})

// Create custom function in parent prototype object
Object.prototype.customFunc = function() {
    console.log('Hi')
}

// create object instance from our object person
const Martin = Object.create(person)
// Primitives
// By default, a primitive does not have a parent object. but if we refer to a primitive in our program as objects through // ".", then an object version of this primitive is temporarily created in memory

let age = 30 // new Number(...) 
let site = 'jottup' // new String(...)
let isActive = true // new Boolean(...)

let promise = new Promise(() => {}) // new Promise(...)
let male = {} // new Object(...)
let peoples = [] // new Array(...)
function subscribeTutorials() {} // new Function(...)
let likeTutorial = function() {} // new Function(...)
let clickTheTutorial = () => {} // new Function(...)
class bestTutorials {} // new Function(...)

let tutorial = new bestTutorials() // new bestTutorials

All objects has property _proto_, but not all objects has prototype

let male = {} // This is an object and the object has __proto__
let peoples = [] // This is an array, basically it is an object on more low js level, object has _proto_

// Primitives
let age = 30 // when accessed as an object, a shell is temporarily created Number(), has _proto_
let site = 'jottup' // when accessed as an object, a shell is temporarily created String(), has _proto_
let isActive = true // when accessed as an object, a shell is temporarily created Boolean(), has _proto_

function subscribeTutorials() {} // created in memory as Function, has _proto_
let likeTutorial = function() {} // created in memory as Function, has _proto_
let clickTheTutorial = () => {} // created in memory as Function, has _proto_
class bestTutorials {} // class it is a Function, syntactic sugar from ES, has _proto_

Moreover, different _proto_ objects of different “type” are completely different objects.
For objects of the same “type” – they are equal, that is, they are one and the same object

let person = {}
let person1 = {}

console.log(person === person1) // False
console.log(person.__proto__ === person1.__proto__) // True

Each prototype is an independent object, in itself, with a certain set of properties and methods. Prototype is either in Class or function.

class Tutorial {}
function Component() {} // is a constructor function, because there is a function
const sum = function() {} // is a constructor function, because there is a function

console.log(Tutorial.prototype)
console.log(Component.prototype)
console.log(sum.prototype)

console.log(Object.prototype)
console.log(Promise.prototype)
console.log(Function.prototype)
console.log(Boolean.prototype)
console.log(Number.prototype)
console.log(String.prototype)
console.log(Array.prototype)

// Extra Cases
const increase = () => {} // the arrow function does not have a prototype because it is not a constructor function!!!

let person = {name: 'John'}
console.log(person.prototype) // prototype not exist, because it wasn't created via class or function
console.log(person.__proto__ === Object.prototype) // True

Prototypal Inheritance

JavaScript’s prototype chain allows for efficient and flexible inheritance. When an object’s property or method is accessed, and it’s not found on the object itself, JavaScript searches up the prototype chain until it finds the property/method or reaches the end of the chain. This mechanism enables powerful inheritance, which is leveraged by many frameworks and libraries.

Prototype inheritance is inheritance from objects. Each entity in javascript has a _proto_ property, which is essentially a reference to the object’s parent prototype.
Both _proto_ and prototype are object properties.
_proto_ of any object refers to the prototype of the class (constructor function) with which this object was created.

let age = 30 // age.__proto__ === Number.prototype
let site = 'jottup' // site.__proto__ === String.prototype
let isActive = true // isActive.__proto__ === Boolean.prototype

let promise = new Promise(() => {}) // promise.__proto__ === Promise.prototype
let male = {} // male.__proto__ === Object.prototype
let peoples = [] // peoples.__proto__ === Array.prototype
function subscribeTutorials() {} // subscribeTutorials.__proto__ === Function.prototype
let likeTutorial = function() {} // likeTutorial.__proto__ === Function.prototype
let clickTheTutorial = () => {} // clickTheTutorial.__proto__ === Function.prototype
class bestTutorials {} // bestTutorials.__proto__ === Function.prototype

let tutorial = new bestTutorials() // tutorial.__proto__ === bestTutorials.prototype

Why does a class need a prototype object?
Why would objects created with this class need a __proto__ property that references this prototype object?

If we are trying to read the property of an object, or call its method, but this property or method does not exist, then the object will climb to look for it through the __proto__ reference in the prototype of the class with which it was created.

let person = {name: 'John'}
person.toString()

// person.__proto__ => Object.prototype = { toString(){} }

The Object.create() Method

ES5 introduced the Object.create() method, providing developers with an alternative way to create objects with specific prototypes. This method allows you to explicitly define the prototype of a newly created object:

const vehiclePrototype = {
  drive() {
    console.log("Vroom vroom!");
  }
};

const myCar = Object.create(vehiclePrototype);
myCar.drive(); // Output: Vroom vroom!

ES6 and Classes

With the advent of ECMAScript 2015 (ES6), JavaScript introduced the class syntax, making object-oriented programming more intuitive for developers coming from class-based languages. Under the hood, classes still utilize prototypes for inheritance.

How works in background Ecmascript classes?

class Tutorial {
    constructor(name) {
        this.name = name
    }
    hello() {
        console.log(this.name)
    }
}

// the same as 

function Tutorial(name) {
    this.name = name
}

Tutorial.prototype.hello = function() {
    console.log(this.name)
}

Manipulating Prototypes

While modifying built-in object prototypes is generally discouraged due to potential conflicts and compatibility issues, it’s essential to understand how prototypes can be manipulated. Remember, changes made to the prototype will affect all instances and derived objects.

Adding Methods to Built-in Objects

Array.prototype.sum = function() {
  return this.reduce((total, num) => total + num, 0);
};

const numbers = [1, 2, 3, 4, 5];
console.log(numbers.sum()); // Output: 15

Changing Prototype Reference

function Animal(name) {
  this.name = name;
}

function Dog(name, breed) {
  this.breed = breed;
}

Dog.prototype = new Animal();
const myDog = new Dog("Buddy", "Golden Retriever");

console.log(myDog instanceof Animal); // Output: true

Posted in Javascript tagged as proto