⚡IntermediateObject-Oriented JavaScript
Prototypes & Inheritance
Understand JavaScript's prototype chain how objects inherit properties, how classes work under the hood, and how to use Object.create.
Overview
Every object in JavaScript has an internal link to another object called its prototype. When you access a property that doesn't exist on an object, JavaScript looks up the prototype chain checking the prototype, then the prototype's prototype, and so on until it finds the property or reaches null.
This prototype chain is the foundation of inheritance in JavaScript. ES6 classes are syntactic sugar on top of this system. When you write class Dog extends Animal, JavaScript sets up Dog.prototype's prototype to be Animal.prototype. Instance methods live on the prototype, not on each individual object so all instances share the same function object, saving memory.
Understanding prototypes helps you debug unexpected behavior, work with legacy code that predates classes, understand how built-in methods like Array.prototype.map work, and write more efficient code. It is also necessary knowledge for working with libraries that manipulate prototypes directly.
Key Points
- •Every object has a [[Prototype]] accessible via Object.getPrototypeOf(obj) or obj.__proto__
- •Property lookup walks up the prototype chain until the property is found or null is reached
- •Object.create(proto) creates an object with proto as its prototype
- •Constructor functions + .prototype is how inheritance worked before ES6 classes
- •Classes compile to constructor functions and prototype assignments under the hood
- •hasOwnProperty(key) checks if a property is directly on the object (not on the prototype)
- •Array.prototype.map, String.prototype.slice, etc. are prototype methods shared by all instances
- •You can add methods to built-in prototypes but this is strongly discouraged (prototype pollution)
Examples
The prototype chain in action
const animal = {
breathe() {
return `${this.name} is breathing`;
}
};
const dog = Object.create(animal);
dog.name = "Rex";
dog.bark = function() {
return `${this.name} barks!`;
};
console.log(dog.bark()); // Rex barks! (own property)
console.log(dog.breathe()); // Rex is breathing (from prototype)
console.log(dog.hasOwnProperty("bark")); // true
console.log(dog.hasOwnProperty("breathe")); // false
console.log(Object.getPrototypeOf(dog) === animal); // trueWhen dog.breathe() is called, JS checks dog not found then checks animal (the prototype) found.
Constructor functions how classes worked before ES6
// Old-style constructor function (equivalent to a class)
function Person(name, age) {
this.name = name;
this.age = age;
}
// Methods go on the prototype shared by all instances
Person.prototype.greet = function() {
return `Hi, I'm ${this.name}`;
};
Person.prototype.toString = function() {
return `Person(${this.name}, ${this.age})`;
};
const alice = new Person("Alice", 30);
const bob = new Person("Bob", 25);
console.log(alice.greet()); // Hi, I'm Alice
console.log(bob.greet()); // Hi, I'm Bob
// Both share the same greet function
console.log(alice.greet === bob.greet); // true
// ES6 class equivalent:
class PersonClass {
constructor(name, age) { this.name = name; this.age = age; }
greet() { return `Hi, I'm ${this.name}`; }
}Prototype chain with Object.create for inheritance
const vehicleProto = {
describe() {
return `${this.make} ${this.model} (${this.year})`;
},
start() {
return `${this.describe()} started`;
}
};
const carProto = Object.create(vehicleProto);
carProto.honk = function() {
return "Beep!";
};
function createCar(make, model, year) {
const car = Object.create(carProto);
car.make = make;
car.model = model;
car.year = year;
return car;
}
const car = createCar("Toyota", "Camry", 2022);
console.log(car.start()); // Toyota Camry (2022) started
console.log(car.honk()); // Beep!
// Prototype chain: car -> carProto -> vehicleProto -> Object.prototype -> null
console.log(car instanceof Object); // trueCommon Mistakes
- Modifying Object.prototype or Array.prototype it affects every object/array and causes conflicts with other code
- Confusing obj.hasOwnProperty(key) with key in obj the in operator also checks the prototype chain
- Thinking that class syntax creates a different system it is still prototype-based underneath
- Accidentally sharing mutable state (like arrays) on the prototype between all instances
Note
Use Object.getPrototypeOf(obj) instead of obj.__proto__ __proto__ is a legacy accessor that is deprecated. To check the full prototype chain for a property, use the in operator: "method" in obj.
Exercises
Write JavaScript code to solve each exercise. Run it and check your output.
Loading editor…
Completed: 0 / 5 exercises
Knowledge Check
Question 1 of 4