Prototypal Inheritance
JavaScript does not use traditional class-based inheritance like Java or C++. Instead, it uses Prototypes—a chain of linked objects that allow for sophisticated behavior sharing and exceptional memory efficiency.
The Prototype Chain
Every object in JavaScript has a internal link to another object called its Prototype. When you access a property that doesn't exist on the object, the engine "walks up" this chain until it finds the property or hits null.
// The Prototype Chain in action
const hardware = {
brand: 'NVIDIA',
type: 'GPU',
specs() {
return `${this.brand} ${this.type}`;
}
};
const vRAM = {
size: '24GB',
// Setting inheritance via Object.create
__proto__: hardware
};
console.log(vRAM.size); // '24GB' (Own Property)
console.log(vRAM.brand); // 'NVIDIA' (Inherited via Chain)
console.log(vRAM.specs()); // 'NVIDIA GPU' (Inherited Method)Memory Efficiency: Prototype vs Instance
Understanding prototypes is crucial for performance. Methods added to a function's prototype are shared across all instances. Methods added inside a constructor are duplicated for every single instance, consuming significantly more memory.
// --- Prototype vs Instance Methods ---
function OptimizedObject(id) {
this.id = id;
}
// ✅ Memory Efficient: All instances share 1 function reference
OptimizedObject.prototype.logId = function() {
console.log(this.id);
};
function InefficientObject(id) {
this.id = id;
// ⌠Memory Leak: Every instance gets a custom function clone
this.logId = function() {
console.log(this.id);
};
}prototypefor methods (behavior) and the constructor for instance-specific data (state).The Pure Object Pattern
Sometimes you need a hash map that is completely empty, without built-in methods like toString or hasOwnProperty. This prevents Prototype Pollution attacks where an attacker might overwrite shared methods.
// Object.create(null) - The High Performance Dictionary
const dictionary = Object.create(null);
// Standard objects have inherited methods like .toString()
console.log({}.toString); // [Function: toString]
// A null prototype object is "Pure" - no inheritance risk
console.log(dictionary.toString); // undefined
// 💡 Ideal for maps where you don't want property pollution.__proto__ vs .prototype
This is the most common point of confusion in JavaScript. The prototype property is used by Constructor Functions to set the prototype of new instances. The __proto__ property is the actual link on the instance itself.
// How 'new' actually works under the hood
function User(name) {
this.name = name;
}
const u1 = new User('Alice');
/*
1. {} is created
2. {}.__proto__ = User.prototype
3. User.call({}, 'Alice')
4. The object is returned
*/
console.log(u1.__proto__ === User.prototype); // trueObject.getPrototypeOf()instead of __proto__ for better performance and compatibility.Technical Recap:
- ✅ Hierarchy: Most objects eventually trace back to
Object.prototype. - ✅ Shadowing: If an object has its own property with the same name as a prototype property, it "shadows" it.
- ✅ Efficiency: Use prototypes to prevent creating 10,000 function instances for 10,000 objects.
- ⌠Mutation: Modifying
Object.prototypeis a major anti-pattern that can break entire libraries. - ✅ Modernity: ES6 Classes use this exact system under the hood; prototypes are the engine, Classes are the dashboard.