
How Inheritance Works in the JavaScript Prototype Chain

This Article is Over Ten Years Old...
Things can and do move very quickly in tech, which means that tech-related articles go out of date almost as soon as they have been written and published. If you are looking for up-to-date technical advice or opinion, it is unlikely that you will find it on this page.
You may find that my recent articles are more relevant, and you are always welcome to drop me a line if you have a specific technical problem you are trying to solve.
In web development, JavaScript is a powerful language with a unique approach to inheritance. It relies on a prototype chain, which is the key to understanding how JavaScript handles object relationships or allows us to reuse methods across multiple objects. Here, I intend to break it down to help us understand how inheritance works in JavaScript.
What is the Prototype Chain?
At its core, the prototype chain is a series of links between objects. Every JavaScript object has an internal property called [[Prototype]], which points to another object or null. This linkage creates a chain that JavaScript traverses whenever it needs to find a property or method that isn't directly on the object itself.
How Does It Work?
1. Searching for Properties:
When you try to access a property on an object, JavaScript first looks for it directly on the object. If the property doesn't exist, it looks at the object's [[Prototype]]. If it still doesn't find the property, it continues traversing the chain until it reaches an object with null as its prototype (the end of the chain).
const parent = { greet: () => 'Hello, world!' };const child = Object.create(parent);console.log(child.greet()); // "Hello, world!"console.log(child.hasOwnProperty('greet')); // falseIn this example, the greet method is not found on child but is found on its prototype, parent.
2. Method Sharing through Prototypes:
Objects created from the same prototype share methods. Instead of each object having its own copy of a method, they reference a single method defined on the prototype.
function Animal(type) { this.type = type;}Animal.prototype.speak = function () { return `${this.type} makes a noise.`;};const dog = new Animal('Dog');const cat = new Animal('Cat');console.log(dog.speak()); // "Dog makes a noise."console.log(cat.speak()); // "Cat makes a noise."In this example, speak is defined once on Animal.prototype and shared among all Animal instances.
3. Adding to the Prototype Chain Dynamically:
You can dynamically add properties or methods to a prototype, and they will be immediately available to all objects inheriting from it.
Animal.prototype.eat = function () { return `${this.type} is eating.`;};console.log(dog.eat()); // "Dog is eating."console.log(cat.eat()); // "Cat is eating."This flexibility can be a bit of a double‑edged sword; whilst it allows for powerful dynamic behaviour, it also risks unintentional changes if not carefully managed.
4. Prototype Chain Limitations:
If a property or method is missing on the entire prototype chain, JavaScript throws an error when you try to invoke it.
console.log(dog.fly()); // TypeError: dog.fly is not a functionThis highlights the importance of ensuring that your code explicitly defines all expected properties and methods.
Prototype vs. __proto__ vs. prototype
[[Prototype]]: The internal reference to the parent object (not directly accessible).__proto__: A legacy getter/setter for [[Prototype]], used to inspect or modify the prototype.prototype: A property specific to functions that defines the [[Prototype]] of objects created by new.
For example:
function Person(name) { this.name = name;}Person.prototype.sayHello = function () { return `Hi, my name is ${this.name}`;};const john = new Person('John');console.log(john.sayHello()); // "Hi, my name is John"Here, Person.prototype is the object used as the prototype for all instances of Person.
Why is the Prototype Chain Important?
Inheritance
: The prototype chain allows objects to inherit properties and methods from other objects without duplicating them.Memory Efficiency
: Instead of creating new copies of methods for every object, JavaScript uses the prototype chain to share methods among instances.Dynamic Extensions
: You can add properties or methods to a prototype, and they immediately become available to all objects inheriting from it.
Common Pitfalls
Overwriting Prototypes:
Replacing the entire prototype can lead to unexpected results, for example:
function Animal() {}Animal.prototype.speak = () => 'Generic sound';const dog = new Animal();Animal.prototype = { speak: () => 'Woof!' };console.log(dog.speak()); // "Generic sound"Here, even though Animal.prototype was overwritten, dog still references the old prototype and, therefore, does not woof.
Prototype Pollution:
Modifying built‑in prototypes (e.g., Array.prototype) can lead to compatibility issues and unexpected bugs.
Wrapping up
The JavaScript prototype chain is fundamental to understanding inheritance and property lookup within the language. We can write more efficient, modular, and maintainable code by grasping how objects and their prototypes interact. Whether we're creating complex applications or simply trying to debug property access, understanding the nuances of prototypes and inheritance can save us countless hours of frustration.
As we've seen, whilst the prototype chain simplifies inheritance and reduces duplication, it also requires careful handling to avoid performance pitfalls and unexpected behaviour. By balancing the power of this mechanism with thoughtful coding practices, we can unlock the full potential of JavaScript's object model.
Key Takeaways
Prototype Chain Basics
: JavaScript uses prototypes to enable inheritance between objects, linking them through a chain for property access.Property Lookup
: The engine searches for properties along the prototype chain, starting with the object itself and moving up until the property is found or the chain ends.Performance
: Accessing properties deeper in the prototype chain can affect performance, so design your objects and inheritance structures wisely.Customisation
: Prototypes can be extended or modified, but doing so globally (e.g., changingObject.prototype) is not at all a good idea due to potential conflicts.Best Practices
: UseObject.create, class syntax, or existing frameworks to manage prototypes in a controlled and predictable manner.
Understanding the JavaScript prototype chain is essential for mastering inheritance and object‑oriented programming in JavaScript. With it, we can create more efficient, scalable, and maintainable code.
Related Articles

Type Coercion in JavaScript: Implicit vs. Explicit Conversion. 
Object Control in JavaScript: defineProperties(). Object Control in JavaScript:
defineProperties()
How to Read JavaScript Errors and Stack Traces. How to Read JavaScript Errors and Stack Traces

Pass by Value vs. Reference in JavaScript. Pass by Value vs. Reference in JavaScript

Break Out of CSS Nesting with Sass. Break Out of CSS Nesting with Sass

Understanding Transient Props in styled‑components. Understanding Transient Props in
styled‑components
Fundamentals of HTML: A Guide. Fundamentals of HTML: A Guide

How to Use grid in CSS. How to Use
gridin CSS
Check If Your Site is Running on localhost. Check If Your Site is Running on
localhost
Mutation vs. Immutability in JavaScript Arrays and Objects. Mutation vs. Immutability in JavaScript Arrays and Objects

Understanding setTimeout() in JavaScript. Understanding
setTimeout()in JavaScript
Creating Interactive User Interfaces with HTML, CSS, and JavaScript. Creating Interactive User Interfaces with HTML, CSS, and JavaScript