What are prototypes in JavaScript, and how does prototypal inheritance work?
Every object has a hidden link to another object called its prototype. When you read a property that the object does not have, JavaScript looks it up along this prototype chain. Classes are syntax built on top of this: methods live on the prototype and are shared by all instances.
Explain it simply
Suppose you ask a junior in your hostel for a calculator. If they do not have one, they ask their senior. If the senior does not have one either, the senior asks the warden. The first person in that chain who has a calculator lends it. If nobody has one, the answer is "not available".
JavaScript objects work exactly like this. Each object has a hidden link to another object, its prototype. When you read obj.something and obj does not have its own something, JavaScript asks the prototype, then the prototype's prototype, and so on. This is the prototype chain. It ends at Object.prototype, whose prototype is null. If the property is not found anywhere, you get undefined.
That is prototypal inheritance: objects inherit directly from other objects, not from class blueprints the way Java does.
Example
const animal = {
eats: true,
describe() {
return this.name + " eats: " + this.eats;
},
};
const dog = Object.create(animal); // dog's prototype is animal
dog.name = "Tommy";
console.log(dog.describe()); // Output: Tommy eats: true
console.log(Object.getPrototypeOf(dog) === animal); // Output: true
console.log(Object.hasOwn(dog, "name")); // Output: true
console.log(Object.hasOwn(dog, "eats")); // Output: false
function Student(name) {
this.name = name;
}
Student.prototype.intro = function () {
return "I am " + this.name;
};
const meera = new Student("Meera");
const arjun = new Student("Arjun");
console.log(meera.intro()); // Output: I am Meera
console.log(meera.intro === arjun.intro); // Output: true
class Topper extends Student {
intro() {
return super.intro() + ", rank 1";
}
}
const riya = new Topper("Riya");
console.log(riya.intro()); // Output: I am Riya, rank 1
console.log(riya instanceof Student); // Output: true
console.log(typeof Topper); // Output: functionmeera.intro === arjun.intro is true because the method is stored once, on Student.prototype, and both objects reach it through the chain. typeof Topper is "function" because a class is a special kind of constructor function.
How it works
Object.create(proto)makes a new object whose prototype isproto.- Every normal function has a
prototypeproperty.new Student("Meera")creates an object, sets its prototype toStudent.prototype, runsStudentwiththisset to that object, and returns it. class Topper extends Studentsets up two links:Topper.prototypeinherits fromStudent.prototype(for methods), andTopperinherits fromStudent(for static methods).- Reading a property walks the chain. Writing a property always creates or updates it on the object itself; it does not change the prototype. This is called shadowing.
instanceofchecks whetherStudent.prototypeappears anywhere in the object's chain.
Real-world use
Every array you create can call map and filter because those methods live once on Array.prototype. Every string has toUpperCase through String.prototype. Classes in React, Angular services and Node's EventEmitter subclasses all rely on the prototype chain. Putting methods on the prototype instead of inside the constructor saves memory when you create thousands of objects.
Common mistakes
- Mixing up
__proto__/Object.getPrototypeOf(obj)(the object's actual link) with a function'sprototypeproperty (the object that will become the prototype of instances created withnew). - Defining methods inside the constructor with
this.intro = function () {}, which creates a new copy for every instance. - Changing built-in prototypes like
Array.prototype. It can break other code and future language features. - Thinking classes make JavaScript use classical inheritance. They are mostly syntax over prototypes.
What to say in the interview
"Every object has an internal link to a prototype object. When a property is not found on the object, the engine looks up the prototype chain until it finds it or reaches null. That is prototypal inheritance: objects inherit from other objects. Constructor functions set up this link through their prototype property when called with new, and ES6 classes are mainly cleaner syntax over the same mechanism, with methods stored once on the prototype and shared by all instances. Writes create own properties and shadow the prototype's, and instanceof works by checking the chain."
Follow-up questions
- What is the difference between
__proto__andprototype? - What exactly does the
newkeyword do, step by step? - How would you create an object with no prototype at all, and why?
Go deeper
Read these once the basics above feel easy.
Object.create(null) creates an object with no prototype, so it has no inherited keys like toString or constructor. That makes it a safer plain dictionary, and it is one defence against prototype pollution, an attack where untrusted input such as {"__proto__": {"isAdmin": true}} is merged into an object and ends up adding properties to Object.prototype, which every object then inherits. Libraries that deep-merge user JSON must skip keys like __proto__, constructor and prototype. For lookups, engines like V8 cache property locations using hidden classes and inline caches, so long prototype chains are rarely a speed problem in practice, but changing an object's prototype after creation with Object.setPrototypeOf can make that code slower.