🟨 JavaScript Q20 / 104

Explain prototype and prototypal inheritance.

AI-Powered Answer ✓ Answered

In JavaScript, prototypes are a fundamental mechanism by which objects inherit features from one another. This object-oriented programming paradigm, known as prototypal inheritance, is distinct from classical inheritance found in languages like Java or C++.

What is a Prototype?

Every JavaScript object has an internal slot called [[Prototype]], which is either null or references another object. This referenced object is known as the object's prototype. When you try to access a property or method on an object, and it's not found directly on that object, JavaScript will look for it on the object's prototype, and then on that prototype's prototype, and so on, until it finds the property or reaches null.

The prototype property (on constructor functions) and the __proto__ accessor property (on object instances) are key to understanding prototypes. The prototype property of a constructor function points to the object that will be set as the [[Prototype]] for instances created by that constructor. The __proto__ property of an object instance points to its actual prototype object.

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

Person.prototype.greet = function() {
  return `Hello, my name is ${this.name}`;
};

const john = new Person('John');

console.log(john.greet()); // Hello, my name is John
console.log(Object.getPrototypeOf(john) === Person.prototype); // true
console.log(john.__proto__ === Person.prototype); // true

Prototypal Inheritance

Prototypal inheritance is a method by which objects can inherit properties and methods from other objects. Instead of classes defining blueprints for objects, in prototypal inheritance, an object can be created from an existing object, inheriting its properties and methods. This forms a 'prototype chain'.

The prototype chain is a series of links between objects. When a property or method is accessed on an object, JavaScript first checks if the object itself has that property. If not, it looks up the chain to the object's prototype. If still not found, it continues up the chain to the next prototype, until it reaches the end of the chain (which is Object.prototype, whose prototype is null). This search mechanism is how inheritance is achieved.

javascript
const animal = {
  eats: true,
  walk() {
    return "Animal is walking";
  }
};

const rabbit = {
  jumps: true,
  __proto__: animal // rabbit inherits from animal
};

const longEar = {
  earLength: 10,
  __proto__: rabbit // longEar inherits from rabbit
};

console.log(rabbit.eats); // true (inherited from animal)
console.log(rabbit.walk()); // Animal is walking (inherited from animal)

console.log(longEar.jumps); // true (inherited from rabbit)
console.log(longEar.eats); // true (inherited from animal via rabbit)
console.log(longEar.walk()); // Animal is walking (inherited from animal via rabbit)

How to Create Objects with Prototypes

  • Object.create(): Creates a new object, using an existing object as the newly created object's prototype.
  • Constructor Functions: Traditional way to create objects in JS, where instances inherit from Constructor.prototype.
  • ES6 Classes: Syntactic sugar over constructor functions and prototypal inheritance, making it look more like classical inheritance.
javascript
const baseObject = {
  message: 'Hello from base!'
};

const newObject = Object.create(baseObject);
console.log(newObject.message); // Hello from base!
console.log(Object.getPrototypeOf(newObject) === baseObject); // true
javascript
function Car(make) {
  this.make = make;
}

Car.prototype.drive = function() {
  return `${this.make} is driving.`;
};

const myCar = new Car('Toyota');
console.log(myCar.drive()); // Toyota is driving.
javascript
class Vehicle {
  constructor(type) {
    this.type = type;
  }
  start() {
    return `${this.type} starting.`;
  }
}

class Bike extends Vehicle {
  constructor(brand) {
    super('Bike');
    this.brand = brand;
  }
  ride() {
    return `${this.brand} bike is riding.`;
  }
}

const myBike = new Bike('Honda');
console.log(myBike.start()); // Bike starting.
console.log(myBike.ride()); // Honda bike is riding.
console.log(Object.getPrototypeOf(myBike) === Bike.prototype); // true
console.log(Object.getPrototypeOf(Bike.prototype) === Vehicle.prototype); // true

Key Takeaways

  • Prototypes are objects: Every JavaScript object has a prototype, which is another object it inherits from.
  • Prototype Chain: When a property is not found on an object, JavaScript looks up the prototype chain until it finds the property or reaches null.
  • Prototypal Inheritance: JavaScript uses prototypal inheritance, not classical inheritance. Objects inherit directly from other objects.
  • prototype vs. __proto__: prototype is a property of constructor functions, __proto__ is an accessor property of object instances (pointing to their actual prototype).
  • Object.create(): A direct way to set an object's prototype.
  • ES6 Classes: Provide a more familiar syntax for object creation and inheritance, but internally still use prototypal inheritance.