Explain the concept of prototypal inheritance in JavaScript.

Prototypal inheritance is a fundamental concept in JavaScript that allows objects to inherit properties and methods from other objects. It is a key feature of JavaScript’s object-oriented programming paradigm.

In JavaScript, every object has an internal property called [[Prototype]] (also referred to as “dunder proto” or “proto”). This [[Prototype]] property references another object, which is the object’s prototype. When accessing a property or method on an object, if it is not found directly on the object itself, JavaScript will look up the prototype chain until it finds the property or until it reaches the end of the chain.

Here’s an example to illustrate prototypal inheritance in JavaScript:

// Creating a prototype object

const vehiclePrototype = {

  start() {

    return ‘Starting the vehicle…’;

  },

  stop() {

    return ‘Stopping the vehicle…’;

  },

};

// Creating a new object using the prototype

const car = Object.create(vehiclePrototype);

car.make = ‘Toyota’;

car.model = ‘Camry’;

console.log(car.make); // Output: Toyota

console.log(car.start()); // Output: Starting the vehicle…

In the example above, we create a vehiclePrototype object that serves as the prototype for other objects. It contains start() and stop() methods.

We then create a new object car using Object.create() and pass vehiclePrototype as the prototype for car. This establishes the prototypal inheritance relationship between car and vehiclePrototype.

The car object inherits the start() and stop() methods from its prototype (vehiclePrototype). We can access the make property defined on the car object directly, as it is defined on the object itself.

When we call car.start(), JavaScript first looks for the start() method on the car object. Since it’s not found, it follows the prototype chain and finds the start() method on the vehiclePrototype object. The method is then executed, and the output is displayed.

This concept of prototypal inheritance allows objects to share behavior and reuse code through the prototype chain. It promotes code reusability and avoids duplicating methods across multiple objects.

It’s important to note that JavaScript objects can have only one prototype ([[Prototype]]), forming a single inheritance chain. However, you can achieve multiple levels of inheritance by creating a chain of objects, where each object inherits from another object.

Here’s an example that demonstrates multiple levels of inheritance:

const vehiclePrototype = {

  start() {

    return ‘Starting the vehicle…’;

  },

  stop() {

    return ‘Stopping the vehicle…’;

  },

};

const carPrototype = Object.create(vehiclePrototype);

carPrototype.drive = function() {

  return ‘Driving the car…’;

};

const electricCarPrototype = Object.create(carPrototype);

electricCarPrototype.charge = function() {

  return ‘Charging the electric car…’;

};

const tesla = Object.create(electricCarPrototype);

tesla.make = ‘Tesla’;

tesla.model = ‘Model S’;

console.log(tesla.make); // Output: Tesla

console.log(tesla.drive()); // Output: Driving the car…

console.log(tesla.start()); // Output: Starting the vehicle…

console.log(tesla.charge()); // Output: Charging the electric car…

In this example, we create multiple levels of inheritance. The vehiclePrototype object serves as the base prototype, followed by the carPrototype object inheriting from vehiclePrototype, and finally, the electricCarPrototype inheriting from carPrototype. The tesla object is created using electricCarPrototype as its prototype.

By leveraging prototypal inheritance, objects can inherit and extend functionality from their prototypes, allowing for code reuse and modularity in JavaScript.