Every JavaScript object has a hidden link to another object, its prototype, and properties not found on the object itself are looked up along this prototype chain. This lesson covers __proto__, constructor function .prototype properties, memory-efficient method sharing, property shadowing, and Object.create() for building custom inheritance chains.
1JS Prototypes & Inheritance - In-Depth Guide Part 1
Prototypes are the 'DNA' of JavaScript objects. They define the hidden mechanisms that allow objects to share methods and properties.
// The Secret DNA of JS2JS Prototypes & Inheritance - In-Depth Guide Part 2
Every object has a hidden link to another object called its 'prototype'. You can see it using '__proto__'.
const animal = { eats: true };
const rabbit = { jumps: true };
rabbit.__proto__ = animal; // Inheritance!3JS Prototypes & Inheritance - In-Depth Guide Part 3
When you look for a property on an object, JS first checks the object itself, then its prototype, then the prototype's prototype...
console.log(rabbit.eats); // true (found in animal)
console.log(rabbit.jumps); // true (found in rabbit)4JS Prototypes & Inheritance - In-Depth Guide Part 4
Constructor functions have a '.prototype' property. Objects created with 'new' will have this as their prototype.
function Bird(name) {
this.name = name;
}
Bird.prototype.fly = () => 'I am flying!';5JS Prototypes & Inheritance - In-Depth Guide Part 5
Putting methods on the prototype is efficient. Every instance shares the SAME function instead of creating a copy.
const b1 = new Bird('Sparrow');
const b2 = new Bird('Eagle');
console.log(b1.fly === b2.fly); // true!6JS Prototypes & Inheritance - In-Depth Guide Part 6
The chain eventually ends at 'Object.prototype'. Its prototype is 'null', which stops the search.
console.log(Object.prototype.__proto__); // null7JS Prototypes & Inheritance - In-Depth Guide Part 7
You can create objects with a specific prototype using 'Object.create(proto)'.
const car = { drive: true };
const tesla = Object.create(car);
console.log(tesla.drive); // true8JS Prototypes & Inheritance - In-Depth Guide Part 8
Property Shadowing: If an object has a property with the same name as its prototype, the object's version is used.
animal.kind = 'Wild';
rabbit.kind = 'Small';
console.log(rabbit.kind); // 'Small'9JS Prototypes & Inheritance - In-Depth Guide Part 9
Prototype chain mastered! You now understand the true engine behind JavaScript inheritance.
<h1>Prototypes: Decoded</h1>10Step-by-Step Breakdown
Prototypes are the 'DNA' of JavaScript objects. They define the hidden mechanisms that allow objects to share methods and properties.
Every object has a hidden link to another object called its 'prototype'. You can see it using '__proto__'.
When you look for a property on an object, JS first checks the object itself, then its prototype, then the prototype's prototype...
Checkpoint: What is the name of the 'hidden link' that connects an object to its prototype?
- āparent
- ā__proto__
- ā.prototype
Constructor functions have a '.prototype' property. Objects created with 'new' will have this as their prototype.
Putting methods on the prototype is efficient. Every instance shares the SAME function instead of creating a copy.
Checkpoint: Why is it memory-efficient to put methods on a constructor's .prototype?
- āIt makes the code run faster
- āAll instances share a single copy of the function
The chain eventually ends at 'Object.prototype'. Its prototype is 'null', which stops the search.
You can create objects with a specific prototype using 'Object.create(proto)'.
Property Shadowing: If an object has a property with the same name as its prototype, the object's version is used.
Final Challenge: Which method checks if a property belongs to the object itself and NOT its prototype?
- āisOwn()
- āhasOwnProperty()
- āexists()
Prototype chain mastered! You now understand the true engine behind JavaScript inheritance.
Level Up š
Advanced cheat sheets, SEO tricks, and interview prep for this topic.
Browser Support
Fully supported.
Fully supported.
Fully supported.
Fully supported.
Accessibility (A11y)
1Extending Native DOM Prototypes Can Silently Remove Built-In Accessible Behavior
Overriding a method on a native element's prototype (e.g. HTMLButtonElement.prototype.click) risks stripping away built-in keyboard handling, like Enter/Space triggering a button ā any custom prototype extension of native elements must explicitly preserve or re-implement that behavior so keyboard-only and screen reader users aren't locked out.
SEO Implications
- 1
Prototype-Based Inheritance Has No Direct SEO Effect but Underpins Framework Rendering Internals
Prototypes aren't visible to search engines, but many frameworks rely on prototype methods internally for component lifecycle and rendering ā a misunderstanding of how methods are shared via prototypes can lead to bugs (like shared mutable state across instances) that affect rendered output crawlers see.
Best Practices
Never Modify Built-In Prototypes Like Array.prototype or Object.prototype
Adding or changing methods on a native prototype (a practice called 'monkey-patching') affects every array or object in the entire application, including third-party libraries, and can silently break `for...in` loops or future JavaScript spec additions that happen to use the same method name.
Use hasOwnProperty() or Object.hasOwn() When Iterating with for...in
A for...in loop iterates over inherited enumerable properties as well as an object's own properties, which can pull in unexpected prototype properties. Guard each iteration with `Object.hasOwnProperty.call(obj, key)` (or the newer `Object.hasOwn(obj, key)`) to only process the object's own properties.
Frequent Bugs
A for...in loop over an object unexpectedly includes properties that were never explicitly set on it.
for...in walks the entire prototype chain, including inherited enumerable properties, not just the object's own. Filter with `if (Object.hasOwn(obj, key))` inside the loop, or use `Object.keys(obj)` instead, which only returns the object's own enumerable properties.
Setting `Constructor.prototype = {...}` as a plain object literal breaks `instanceof` checks and loses the constructor reference.
Replacing .prototype entirely with a new object literal removes the automatically-created `constructor` property pointing back to the constructor function. Either add methods individually with `Constructor.prototype.method = ...`, or explicitly reset `Constructor.prototype.constructor = Constructor` after replacing it.
Real-World Examples
Sharing Methods Across Instances with Constructor Functions
Before ES6 classes existed (and equivalently under the hood today), a game needed many Enemy instances that all shared the same takeDamage() logic without each instance carrying its own copy of the function in memory.
function Enemy(name, health) {
this.name = name;
this.health = health;
}
Enemy.prototype.takeDamage = function(amount) {
this.health -= amount;
if (this.health <= 0) console.log(`${this.name} defeated!`);
};
const goblin = new Enemy('Goblin', 30);
const orc = new Enemy('Orc', 50);
console.log(goblin.takeDamage === orc.takeDamage); // true