Understanding Prototypes and Inheritance in JavaScript
Clear, original guide explaining JavaScript prototype inheritance, the prototype chain, constructor functions, and practical examples.
Drake Nguyen
Founder · System Architect
Introduction
JavaScript is a prototype-based language where objects inherit behavior by linking to other objects rather than by instantiating classes. This article explains JavaScript prototype inheritance and the prototype chain, shows how constructor function JavaScript patterns work, and gives practical examples for adding methods to prototypes and setting up inheritance.
JavaScript prototypes and the internal [[Prototype]]
Every object in JavaScript has an internal slot often referred to as [[Prototype]] (exposed in some engines as __proto__). When you try to read a property, the runtime looks first on the object itself and then follows the prototype chain until it finds the property or reaches the end at Object.prototype.
Inspecting an object's prototype
const a = {};
// preferred: read the internal prototype
Object.getPrototypeOf(a); // typically returns Object.prototype
// legacy, not recommended for production
a.__proto__;
Note:__proto__is a legacy accessor. UseObject.getPrototypeOffor reliable behavior across environments.
Prototype chain and property lookup
The prototype chain is the sequence of objects followed during property lookup. For example, an array instance delegates to Array.prototype, which itself delegates to Object.prototype. That path is what we mean by the prototype chain.
- Property lookup begins on the instance and walks the prototype chain.
- The chain ends when the lookup reaches
Object.prototype, whose prototype isnull. - Operators and helpers:
instanceofchecks if a constructor'sprototypeexists in an object's prototype chain;isPrototypeOfis another way to test the relationship.
Examples: Array chain and instanceof
const arr = [];
Object.getPrototypeOf(arr) === Array.prototype; // true
Object.getPrototypeOf(Array.prototype) === Object.prototype; // true
arr instanceof Array; // true
Array.prototype.isPrototypeOf(arr); // true
Constructor functions and adding methods to prototypes
Before ES6 classes, constructor function JavaScript patterns were a common way to create object templates. A constructor is any function used with new. Methods shared by instances are typically attached to the constructor's prototype so they are stored once and reused by all instances.
Constructor example
// Define a constructor
function Player(name, lvl) {
this.name = name;
this.level = lvl;
}
// Add a method to the prototype for reuse
Player.prototype.introduce = function() {
return `${this.name} (level ${this.level})`;
};
const p = new Player('Asha', 3);
p.introduce(); // "Asha (level 3)"
Setting up inheritance with constructor functions
To share prototype methods between constructors, you link prototypes. One approach is to set the child constructor's prototype to inherit from the parent constructor's prototype. Avoid copying instance properties with call alone because that does not establish a prototype relationship.
Child constructors and linking prototypes
function Knight(name, lvl, weapon) {
Player.call(this, name, lvl); // borrow Player instance properties
this.weapon = weapon;
}
// Link prototypes so Knight instances delegate to Player.prototype
Object.setPrototypeOf(Knight.prototype, Player.prototype);
Knight.prototype.attack = function() {
return `${this.name} attacks with ${this.weapon}`;
};
const k = new Knight('Bran', 2, 'sword');
// Methods from both Knight.prototype and Player.prototype are available
k.attack(); // "Bran attacks with sword"
k.introduce(); // "Bran (level 2)"
Alternative: create the child prototype from the parent prototype using Object.create to avoid modifying existing prototype objects.
Using Object.create for safer prototype inheritance
Knight.prototype = Object.create(Player.prototype);
Knight.prototype.constructor = Knight;
Common questions and differences
- Difference between
__proto__andprototype:prototypeis a property on functions used when creating instances;__proto__(or the internal [[Prototype]]) is the reference an object uses to delegate. Object.getPrototypeOfvs__proto__: preferObject.getPrototypeOffor standards-compliant reads; useObject.setPrototypeOforObject.createto change/link prototypes if necessary.prototype chain ends at Object.prototype: attempts to go past that point returnnull.
Best practices for JavaScript prototype inheritance
- Prefer composition or ES6 classes for clear intent in new code, but understanding prototypal inheritance remains essential for legacy and deeper JavaScript knowledge.
- Attach shared methods to prototypes (e.g., how to add methods to a constructor function prototype) rather than recreating them per instance.
- Use
Object.getPrototypeOf,Object.setPrototypeOf, andObject.createcarefully—changing prototype chains at runtime can hurt performance.
Conclusion
JavaScript prototype inheritance is a powerful delegation model that underpins objects and inheritance in the language. By learning how the prototype chain, constructor function JavaScript patterns, and prototype utilities (Object.getPrototypeOf, Object.setPrototypeOf, Object.create) work, you can design efficient and maintainable object relationships and avoid common pitfalls.