Prototypal Inheritance in JavaScript

JavaScript is an object-oriented language that offers various methods for working with objects and inheritance. However, JavaScript's approach to inheritance, called Prototypal Inheritance, can sometimes be confusing for beginners, especially since it differs from the classical class-based inheritance mechanisms seen in other languages. In this article, we will dive deep into what Prototypal Inheritance is, how it works, how to use it, and how it differs from other inheritance methods.

What is Prototypal Inheritance?

Prototypal Inheritance is a mechanism in JavaScript that allows one object to inherit the properties and methods of another object. This means that an object can acquire features from another object's prototype. In JavaScript, every object has a prototype (parent object). If a property or method is not found in an object itself, it is looked up in the object's prototype.

Prototypal inheritance is different from classical inheritance because each object is directly derived from another object, and relationships between classes are established through prototypes.

Prototypes and the proto Property in JavaScript

Each JavaScript object has a prototype. These prototypes may differ depending on how the object is created. When you create an object, its prototype is considered its "parent object."

The proto Property

Each JavaScript object has a __proto__ property that points to its prototype. This property indicates which prototype the object is associated with. If a property or method is not found in an object, JavaScript will automatically look for it in the prototype chain, which is the sequence of prototypes associated with the object.

The Prototype Chain

An object can access properties and methods through its prototype. If the object doesn't have the property or method, JavaScript will look for it in the prototype chain. The chain continues all the way up to the top-level prototype.

For example, in the following code:

const human = {
  name: 'Ahmet',
  age: 30,
  greet: function() {
    console.log('Hello, my name is ' + this.name);
  }
};

const student = Object.create(human);
student.school = 'University';

Here, the student object takes human as its prototype. This means that the student object inherits the greet method and the name and age properties from the human object.

console.log(student.name); // Ahmet
student.greet(); // Hello, my name is Ahmet

In this example, the student object inherits the properties and methods of the human object, and since it doesn't have its own greet method, JavaScript looks for it in the human object.

Creating Objects with Prototypal Inheritance

In JavaScript, you can create new objects and inherit properties and methods using prototypal inheritance. This is often done using the Object.create() method. The Object.create() method creates a new object and uses the given prototype to establish the new object.

Creating Objects with Object.create()

const person = {
  introduce: function() {
    console.log(`Hello, my name is ${this.name}`);
  }
};

const ali = Object.create(person);
ali.name = 'Ali';
ali.introduce(); // Hello, my name is Ali

In this example, the ali object is created with person as its prototype. The introduce method is added to the prototype, and the ali object inherits this method.

Prototypal Inheritance with Constructor Functions

In JavaScript, you can also use constructor functions to create objects and set up inheritance. A constructor function creates an object and automatically associates it with a prototype.

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

Animal.prototype.introduce = function() {
  console.log(`Hello, my name is ${this.name}`);
};

const cat = new Animal('Kara');
cat.introduce(); // Hello, my name is Kara

Here, the Animal constructor function creates a new object, and the introduce method is added to its prototype. The cat object inherits this method.

ES6 Classes and Prototypal Inheritance

With ES6, JavaScript introduced the class syntax, allowing developers to work with inheritance more similarly to traditional object-oriented languages. However, under the hood, classes still use prototypal inheritance.

class Animal {
  constructor(name) {
    this.name = name;
  }

  introduce() {
    console.log(`Hello, my name is ${this.name}`);
  }
}

const cat = new Animal('Kara');
cat.introduce(); // Hello, my name is Kara

In this example, we used the ES6 class syntax to create an Animal object. The introduce method is still inherited through the prototype of the class.

Advantages of Prototypal Inheritance

  • More Flexible: Prototypal inheritance provides a more flexible structure in JavaScript. Each object can inherit from another object, making it easy to create dynamic and customizable behaviors.
  • Dynamic Behaviors: Prototypes allow methods and properties to be added to objects dynamically at runtime, making it useful for extending functionality during the execution of a program.
  • Less Memory Consumption: Since methods are defined once on the prototype rather than for each individual object, it saves memory and makes the code more efficient.

Conclusion

Prototypal Inheritance is a core concept in JavaScript that allows objects to inherit properties and methods from other objects. Unlike class-based inheritance in other languages, JavaScript uses prototypes to establish relationships between objects. Understanding how prototypal inheritance works is essential for every JavaScript developer, as it can significantly improve your ability to write efficient and clean code.

Whether you're using constructor functions or ES6 classes, you’re still working with prototypal inheritance behind the scenes. Mastering this concept will help you better understand how objects work in JavaScript and improve your programming skills.