Prototypal Inheritance

Sridhar MuraliSridhar Murali
3 min read

🧠 What is Prototypal Inheritance?

In JavaScript, objects can inherit properties and methods from other objects. This is known as prototypal inheritance.

Unlike classical languages (like Java, C++) that use classes, JavaScript uses prototypes under the hood to enable inheritance.


🔗 The Prototype Chain

Every JavaScript object has an internal link to another object called its prototype, accessible via [[Prototype]] or .prototype.

When you access a property or method:

  1. JS looks for it on the object itself.

  2. If not found, it goes to its prototype.

  3. If still not found, it keeps walking up the prototype chain.

  4. Ends at Object.prototype, whose prototype is null.

Example:

const person = {
  greet() {
    console.log("Hello!");
  }
};

const john = Object.create(person); // john inherits from person
john.name = "John";

john.greet(); // "Hello!" — inherited from person

➡️ john doesn’t have greet, so it looks up the prototype chain to person.


🧬 How to Create Inheritance

const animal = {
  eats: true
};

const dog = Object.create(animal);
dog.barks = true;

console.log(dog.eats);  // true (inherited)
console.log(dog.barks); // true (own property)
  • Object.create(proto) creates a new object and sets its [[Prototype]] to proto.

2. Constructor Functions + .prototype

Before ES6 classes, we used constructor functions:

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

Person.prototype.sayHello = function () {
  console.log("Hi, I'm " + this.name);
};

const alice = new Person("Alice");
alice.sayHello(); // Hi, I'm Alice

Here’s what happens:

  • alice.__proto__ === Person.prototype

  • JS finds sayHello on Person.prototype via prototype chain.


3. ES6 class Syntax (syntactic sugar)

class Animal {
  speak() {
    console.log("Animal speaks");
  }
}

class Dog extends Animal {
  bark() {
    console.log("Woof!");
  }
}

const d = new Dog();
d.speak(); // Animal speaks
d.bark();  // Woof!

Under the hood, it’s still using prototypes, just more readable.


🔍 Behind the Scenes

Let’s say:

const obj = {};

This creates:

obj --> Object.prototype --> null

If we do:

const animal = {
  speak() {
    return "grrr";
  }
};

const dog = Object.create(animal);
dog.bark = () => "woof";

dog.bark();    // "woof" → from dog
dog.speak();   // "grrr" → inherited from animal

⚙️ __proto__ vs .prototype

TermMeaning
obj.__proto__Refers to the object's internal [[Prototype]]. Used for lookup.
Func.prototypeUsed to define methods that should be inherited by all instances created with new Func()

🛠 Real-World Example

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

Vehicle.prototype.drive = function () {
  return this.name + " is driving";
};

function Car(name) {
  Vehicle.call(this, name); // inherit properties
}

Car.prototype = Object.create(Vehicle.prototype); // inherit methods
Car.prototype.constructor = Car;

const honda = new Car("Honda");
console.log(honda.drive()); // Honda is driving

📚 Summary

ConceptExplanation
PrototypeAn object that other objects inherit from.
Object.create()Creates a new object with a specific prototype.
.prototypeUsed to define methods that are shared across all instances.
__proto__ / [[Prototype]]Points to the object’s prototype, used in property lookup.
Prototype ChainThe lookup mechanism that traverses up the chain if a property/method isn't found.

🚨 Gotchas & Tips

  • Changing __proto__ directly is discouraged (use Object.setPrototypeOf() or Object.create()).

  • You can override inherited methods — the object's own method always wins.

  • Be cautious of deep prototype chains — they can lead to performance hits and hard-to-debug errors.

0
Subscribe to my newsletter

Read articles from Sridhar Murali directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Sridhar Murali
Sridhar Murali

Passionate Frontend Engineer with over 4.5 years of experience in frontend development and a strong previous experience in Quality Assurance of 4 years (2016-2020). Skilled in building responsive, high-quality applications using JavaScript frameworks like Ember.js and React.js, combining meticulous attention to detail from a QA background with a commitment to delivering seamless user experiences. Recognized for writing efficient, accessible code, strong debugging skills