JavaScript prototypes and class inheritance
See that classes are built on prototype chains, and extend one constructor from another.
On this page
JavaScript functions and objects.
- See that classes are built on prototype chains, and extend one constructor from another.
- Predict the sample output and explain the state changes.
- Complete the practice task and check the boundary cases.
The concept
Every JavaScript object has a hidden link to a prototype object. When a property is not found on the object itself, the engine looks it up along the chain of prototypes. A constructor function sets up new objects with this, and methods placed on Constructor.prototype are shared by all instances instead of being copied.
The class syntax is a cleaner way to write the same thing. class Dog extends Animal sets Dog.prototype's prototype to Animal.prototype, and super.method() calls the parent's version. instanceof checks the prototype chain. A method defined on the prototype is not an own property of the instance, which Object.hasOwn shows.
Code example
function Animal(name) {
this.name = name;
}
Animal.prototype.speak = function () {
return this.name + " makes a sound";
};
const rex = new Animal("Rex");
console.log(rex.speak(), Object.getPrototypeOf(rex) === Animal.prototype);
class Dog extends Animal {
speak() {
return super.speak() + " (woof)";
}
}
const fido = new Dog("Fido");
console.log(fido.speak());
console.log(fido instanceof Dog, fido instanceof Animal, Object.hasOwn(fido, "speak"));Rex makes a sound true Fido makes a sound (woof) true true false
Follow the code
Open the walkthrough to inspect the example one step at a time.
Show guided walkthrough
function Animal(name) { this.name = name;}Animal.prototype.speak = function () { return this.name + " makes a sound";}; const rex = new Animal("Rex");console.log(rex.speak(), Object.getPrototypeOf(rex) === Animal.prototype); class Dog extends Animal { speak() { return super.speak() + " (woof)"; }} const fido = new Dog("Fido");console.log(fido.speak());console.log(fido instanceof Dog, fido instanceof Animal, Object.hasOwn(fido, "speak"));Follow the example
Start to inspect the source, values, and output. These prepared steps explain the published sample; grouped loop steps describe multiple iterations.
View the complete dry-run table
| Step / line | What happens | State after step | Output so far |
|---|---|---|---|
| One shared function on the prototype, not one copy per animal. | — | — | |
| new creates an object whose prototype is Animal.prototype. | — | — | |
| speak is found on the prototype, and the link is confirmed. | — | Rex makes a sound true | |
| Dog.prototype inherits from Animal.prototype. | — | Rex makes a sound true | |
| super calls the parent's method and the child adds to the result. | — | Rex makes a sound true | |
| Dog's speak runs first and calls Animal's. | — | Rex makes a sound true Fido makes a sound (woof) | |
| fido is a Dog and an Animal. The speak method lives on the prototype, not on fido. | — | Rex makes a sound true Fido makes a sound (woof) true true false |
Behind the scenes
How JavaScript processes this code
A JavaScript engine parses and runs the source. A function body runs when the function is called. console.log writes to the console.
Cost and common mistakes
Property lookup walks the prototype chain: O(depth of the chain).
- Calling a constructor function without new sets this to undefined (in strict mode) or the global object, so use classes, which refuse to be called without new.
- Changing a prototype affects every instance, including existing ones. Do not modify built-in prototypes such as Array.prototype.
- Extending built-ins and deep inheritance hierarchies are usually worse than composition.
Try it yourself
What does rex.hasOwnProperty("name") return?
Reveal answer and reasoning
true, because name was assigned on the object itself by the constructor.