In most languages, inheriting means receiving a copy of the parent class blueprint. JavaScript does something else: it links one object to another and lets it forward its questions.
The difference is not cosmetic. It explains why a method added after the fact becomes available on objects created long before, and why class never introduced a real class system.
Definition
Prototypal inheritance means giving an object a Prototype, that is, another object it delegates the properties it does not own to. Nothing is copied: the lookup happens on every read, walking up the chain.
const animal = {
introduce() {
return "I am " + this.name;
},
};
const dog = Object.create(animal);
dog.name = "Rex";
console.log(dog.introduce()); // I am Rex
console.log(dog.hasOwnProperty("introduce")); // false
console.log(animal.isPrototypeOf(dog)); // truedog only owns name. The method comes from animal, and this still refers to dog, because its value depends on the object the call is written on.
Classes write exactly the same thing
class and extends are syntax laid on top of this mechanism. The result is the same chain of objects.
class Animal {
constructor(name) { this.name = name; }
introduce() { return "I am " + this.name; }
}
class Dog extends Animal {
introduce() { return super.introduce() + ", a dog"; }
}
const rex = new Dog("Rex");
console.log(rex.introduce()); // I am Rex, a dog
console.log(Object.getPrototypeOf(Dog.prototype) === Animal.prototype); // true
console.log(rex instanceof Animal); // trueThe super inside the overridden method does nothing magical: it calls the version found one step higher in the chain.
Three traps worth knowing
- An object shared on the prototype is shared for good. An array placed there is the same for every instance, and a change made by one changes it for all.
- A written property never travels upward. Assigning
dog.introducecreates an own property that shadows the prototype one, leaving the original untouched. - Deep chains cost readability. Three levels of inheritance and it gets hard to say where a method comes from. Composition is often preferable.
To share behavior without building a hierarchy, Object.assign() copies methods straight onto an object. The result is not inheritance, but it answers the same need in many cases.
Frequently asked questions
Should I prefer Object.create() or class?
Both produce the same structure, so the choice is about readability and team habits. class is the expected form in most projects today, and tooling understands it better. Object.create() remains valuable for composing objects without a constructor, or for creating an object with no prototype at all.
Can an object inherit from several objects at once?
No, the chain is linear: an object has exactly one prototype. To combine several behaviors, the common practice is the mixin, an object of methods copied onto the target prototype with Object.assign(). It is not multiple inheritance, but it covers the same need with no resolution ambiguity.
Why do my instances share an array I thought was their own?
Because it was declared on the prototype instead of inside the constructor. A primitive value creates the illusion that it works, since writing creates an own property. An array or an Object is read and then modified in place, so it stays shared. Always initialize those values in the constructor.