Everything about Prototypal Inheritance: Advanced Javascript

Vamsi Krishna Kodimela
Angular Simplified
Published in
3 min readJan 17, 2024

Objects in Javascript are not just data containers; they’re more like interconnected puzzle pieces with hidden depths. This depth comes in the form of the prototype chain, a mystical concept that governs inheritance and can leave new developers scratching their heads.

Let’s explore the prototypal inheritance in a simplified way and master advanced Javascript.

As I mentioned earlier, consider objects as interconnected puzzle pieces. Each piece is connected to the other via a hidden link called a prototype. Any property or method we tried to access is not found in its own set then the object searches in its prototype. If found, it’ll be used otherwise searches continue in this object’s prototype. This search continues until reaching the ultimate ancestor, the Object.prototype, which marks the end of the line. This search forms a prototype chain.

const person = { name: "Simplified Ninja" };
const employee = { salary: 50000 };

// Link employee to inherit from person
employee.__proto__ = person;

console.log(employee.name); // Output: "Simplified Ninja" (inherited from person)

In this employee object inherits its name property from its parent, the person object

Everyone can own the sword. Only the one master it, win the battle.

Concepts of Inheritance

Now let’s get our hands dirty by digging a little deeper into the concepts of inheritance to make your code more dynamic and clean.

1. Prototypal Inheritance: The Native Approach

  • JavaScript’s fundamental inheritance model is prototypal inheritance. The one we saw in our intro.
  • It’s flexible and dynamic, allowing us to create inheritance relationships directly between objects at runtime.
  • This approach is powerful but requires careful management to avoid hidden dependencies and unexpected behavior.

2. Constructor Functions: Blueprints for Objects

  • Constructor functions offer a more structured approach to creating objects with shared properties and methods. Here’s how they work:
function Animal(name) {
this.name = name;
}
Animal.prototype.eat = function() {
console.log(`${this.name} is eating.`);
};

function Rabbit(name) {
Animal.call(this, name); // Inherit from Animal
this.hop = function() {
console.log(`${this.name} is hopping!`);
};
}
Rabbit.prototype = Object.create(Animal.prototype); // Set prototype chain

const bunny = new Rabbit("Bun-bun");
bunny.eat(); // Output: "Bun-bun is eating." (inherited from Animal)
bunny.hop(); // Output: "Bun-bun is hopping!" (specific to Rabbit)
  • Constructor functions create distinct object blueprints, defining properties and methods on their prototype objects.
  • This promotes code organization and maintainability.

3. Classes (ES6): Syntactic Sugar for Inheritance

  • JavaScript’s ES6 introduced the class syntax as a more familiar way to define constructors and prototypes, resembling classical object-oriented languages:
  • This is the most used approach in real-world projects.
class Animal {
constructor(name) {
this.name = name;
}
eat() {
console.log(`${this.name} is eating.`);
}
}

class Rabbit extends Animal {
hop() {
console.log(`${this.name} is hopping!`);
}
}

const bunny = new Rabbit("Bun-bun");
bunny.eat(); // Output: "Bun-bun is eating." (inherited from Animal)
bunny.hop(); // Output: "Bun-bun is hopping!" (specific to Rabbit)
  • Classes offer a cleaner syntax but ultimately rely on the same prototype chain mechanism behind the scenes.

--

--