JavaScript doesn’t have classical inheritance like Java or C++. Instead, it uses prototypal inheritance — objects inherit directly from other objects. Every object has a hidden link to another object called its prototype.
Every object has a [[Prototype]]
When we create an object, JavaScript secretly links it to another object — its prototype. We can access this link using Object.getPrototypeOf(obj) or the older __proto__ property.
const user = { name: "Manish" };
console.log(Object.getPrototypeOf(user)); // Object.prototype
console.log(user.__proto__); // same thing (older way)
console.log(user.__proto__ === Object.prototype); // true
The Prototype Chain
When we try to access a property on an object, JavaScript first looks at the object itself. If it doesn’t find it there, it goes up to the prototype. If it’s not there either, it goes to the prototype’s prototype, and so on — until it hits null.
function Animal(name) {
this.name = name;
}
Animal.prototype.speak = function() {
console.log(`${this.name} makes a sound`);
};
const dog = new Animal("Buddy");
dog.breed = "Lab";
dog.breed; // "Lab" — found on dog itself
dog.speak(); // found on Animal.prototype
dog.toString(); // found on Object.prototype
dog.randomProp; // undefined — not found anywhere in the chain
Object.create() for Prototypal Inheritance
Object.create() creates a new object and sets its prototype to whatever we pass in:
const animal = {
speak() {
console.log(`${this.name} makes a sound`);
}
};
const dog = Object.create(animal);
dog.name = "Buddy";
dog.speak(); // "Buddy makes a sound"
console.log(Object.getPrototypeOf(dog) === animal); // true
Constructor Functions and prototype
When we use new with a function, the created object’s __proto__ is set to the constructor’s prototype property.
function Person(name) {
this.name = name;
}
Person.prototype.greet = function() {
console.log(`Hi, I'm ${this.name}`);
};
const manish = new Person("Manish");
manish.greet(); // "Hi, I'm Manish"
// The chain:
// manish.__proto__ === Person.prototype → true
// Person.prototype.__proto__ === Object.prototype → true
Methods defined on prototype are shared across all instances — they exist only once in memory, not copied to each instance.
hasOwnProperty() vs in operator
When checking if a property exists, there’s an important difference:
hasOwnProperty()— only checks the object itself, NOT the prototype chaininoperator — checks the object AND the entire prototype chain
function Car(model) {
this.model = model;
}
Car.prototype.wheels = 4;
const car = new Car("Civic");
car.hasOwnProperty("model"); // true — own property
car.hasOwnProperty("wheels"); // false — it's on the prototype
"model" in car; // true — found on object
"wheels" in car; // true — found on prototype chain
Use hasOwnProperty() when we want to check only the object’s own properties (like when iterating with for...in and we want to skip inherited ones).
for (const key in car) {
if (car.hasOwnProperty(key)) {
console.log(key); // only "model", not "wheels"
}
}
In simple language, JavaScript doesn’t copy properties from parent to child. Instead, it creates a chain of links between objects. When we access a property, JS walks up this chain until it finds it (or reaches the end). This is prototypal inheritance — and it’s how everything in JavaScript works under the hood, including classes.