support@90-10.dev

JavaScript Prototypes

Prototypes, a concept unique to JavaScript, is a powerful way to add functionality (properties and methods) to objects.

The Prototype Object

In JavaScript, every object has an internal prototype property which allows an object to inherit properties and methods from another object.

When you create a new object in JavaScript, it inherits all the properties and methods from its prototype. This is called prototypal inheritance and allows us to create complex objects by reusing existing code.

The prototype property is an object itself, and it's accessed using the __proto__ property or the Object.getPrototypeOf() method.

Using a Prototype

Object.create()

The Object.create() method can be used to create an object with a specified prototype object and properties:

const personPrototype = {
    sayHello: function() {
        console.log(`Hello ${this.name}`);
    }
};

let person = Object.create(personPrototype, {
    name: { value: 'Paul' }
});
person.sayHello();  // prints: Hello Paul

console.log(person.__proto__);  
  // prints: "{ sayHello: [Function: sayHello] }"

Object properties can also be set after the object was created:

let person = Object.create(personPrototype);
person.name = 'Paul';
person.sayHello();  // prints: Hello Paul

Object.setPrototypeOf

We can use Object.setPrototypeOf to set a prototype after an object has been created:

let person = {
    name: 'Paul'
};
person.sayHello();  // Uncaught TypeError: 
      // person.sayHello is not a function


const personPrototype = {
    sayHello: function() {
        console.log(`Hello ${this.name}`);
    }
};
Object.setPrototypeOf(person, personPrototype);


person.sayHello();  // prints: Hello Paul

Using __proto__

let developer = {
    language: 'JavaScript'
};

let person = {
    name: 'Paul',
    __proto__: developer
};

console.log(person.name);      // prints: Paul
console.log(person.language);  // prints: Paul

new keyword

Objects can also be created using a constructor function:

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

var person = new Person("Paul");

In this instance, methods can be added to the Person.prototype object directly:

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

Person.prototype.sayHello = function() {
    console.log(`Hello ${this.name}`);
};

var person = new Person("Paul");
person.sayHello();  // prints: Hello Paul

Overriding a Prototype Method

A prototype method can be overridden simply by assigning a new value:

const personPrototype = {
    sayHello: function() {
        console.log(`Hello ${this.name}`);
    }
};

let person = Object.create(personPrototype, {
    name: { value: 'Paul' }
});
person.sayHello();  // prints: Hello Paul


// Override the `sayHello` method
person.sayHello = function() {
    console.log(`Good afternoon ${this.name}`);
};

person.sayHello();  // prints: Good afternoon Paul

Prototype Chain

Here is a prototype chain that will make things a bit clearer. Remember, a prototype is simply an object itself:

const personPrototype = {
    name: 'World'
    sayHello: function() {
        console.log(`Hello ${this.name}`);
    }
};

let person = Object.create(personPrototype);


// the `person` object will serve as the prototype
// for a new `paul` object

let paul = Object.create(person, {
    name: { value: 'Paul' }
});
paul.sayHello();  // prints: Hello Paul

Notice that the paul object doesn't have a sayHello method so JavaScript looks for it in its prototype chain and finds the sayHello method on the personPrototype object.

Introspection

You can check an object's prototype using the instanceof operator or the Object.getPrototypeOf()

const personPrototype = {
    sayHello: function() {
        console.log(`Hello ${this.name}`);
    }
};

let person = Object.create(personPrototype, {
    name: { value: 'Paul' }
});

console.log(person.__proto__);  
  // prints: "{ sayHello: [Function: sayHello] }"

console.log(person instanceof Object); // true
console.log(Object.getPrototypeOf(person) === personPrototype); // true

Take Away

JavaScript prototypes are a powerful feature of the language that allow for easy code reuse and inheritance:

  • Every object in JavaScript has a prototype, except for the Object.prototype object which is the root of the prototype chain. When you try to access a property or method on an object, JavaScript first looks for it on the object itself. If it's not found, it looks for it on the object's prototype, and so on up the prototype chain until it reaches Object.prototype.
  • The Object.setPrototypeOf() method can be used to set an object's prototype, but not recommended due to possible negative impact on performance.
  • The prototype property is accessed using the __proto__ property or the Object.getPrototypeOf() method.
  • When you create an object using a constructor function with the new keyword, JavaScript automatically sets the object's prototype to be the prototype property of the constructor function.
  • You can check an object's prototype using the instanceof operator or the Object.getPrototypeOf()