JavaScript Prototypal Inheritance
Understand the prototype chain, Object.create, and how class syntax wraps prototypal inheritance.
TL;DR
- 01Inherit object properties dynamically through a linked chain of prototypes.
- 02Construct prototype linkages directly using the standard
Object.createmethod. - 03Use modern
classdeclarations as syntactic sugar over prototype chains.
Tips
- 01Use the standard
Object.getPrototypeOf()method instead of legacy properties like__proto__to inspect prototypes. - 02Verify own object properties explicitly using
Object.hasOwn()before accessing inherited properties.
Warnings
- 01Avoid setting object prototypes dynamically using
Object.setPrototypeOfbecause it degrades property access performance. - 02Filter properties inside
for...inloops to prevent iteration leaks from inherited enumerable method names.
The Prototype Chain
Prototype linkageLinks objects together in a prototype chain for sharing property values.
const animal = { eats: true };
const rabbit = Object.create(animal);
rabbit.hops = true;
console.log(rabbit.eats); // trueChain lookup rulesWalks up prototype chains until matching properties are found.
// Lookup: rabbit -> animal -> Object.prototypeChain endEnds prototype search trees at Object.prototype, which has null prototype.
const proto = Object.getPrototypeOf(
Object.prototype
);
console.log(proto); // nullCreating Prototypes
Object.createCreates new object instances with explicit prototype mappings.
const base = { greet() { return "hi"; } };
const obj = Object.create(base);
console.log(obj.greet()); // "hi"Inspecting prototypesInspects prototype references using getPrototypeOf cleanly.
Object.getPrototypeOf(obj) === base; // trueInheritance without classesModels inheritance associations directly without requiring constructors.
const parent = { val: 42 };
const child = Object.create(parent);Constructor prototype
Constructor functionsAttaches shared functions directly to constructor prototype properties.
function Dog(name) { this.name = name; }
Dog.prototype.bark = function() {
return `${this.name} barks`;
};
const rex = new Dog("Rex");Memory optimizationShares method references across all constructed instances.
// rex.bark links to Dog.prototype.barkinstanceof verificationConfirms prototype links exist in target instance chains.
console.log(rex instanceof Dog); // trueClass Sugar
class keywordCompiles class helper blocks to standard prototypes.
class Dog {
constructor(name) { this.name = name; }
bark() { return `${this.name} barks`; }
}
typeof Dog; // "function"Subclass extendsSets up prototype chains between parent and child automatically.
class Puppy extends Dog {
bark() { return super.bark() + "!"; }
}Property Shadowing
hasOwn checkChecks property existence directly on the local object instance.
const base = { color: "red" };
const item = Object.create(base);
console.log(Object.hasOwn(item, "color")); // falseProperty overridesShadows prototype property definitions by setting local values.
item.color = "blue";
console.log(item.color); // "blue"
console.log(base.color); // "red"In Practice
Demonstrates how modern ES6 classes are transformed into prototype constructors under the hood.
- 01Create a base constructor function to assign user properties.
- 02Attach the login method to the user constructor prototype.
- 03Create a subclass admin constructor calling the parent constructor context.
- 04Bind the admin prototype to a new object inheriting from the user prototype.
- 05Reset the admin constructor reference to point to itself correctly.
function createCompilledClass() {
function User(name) {
this.name = name;
}
User.prototype.login = function() {
return this.name + " logged in";
};
function Admin(name, role) {
User.call(this, name);
this.role = role;
}
Admin.prototype = Object.create(
User.prototype
);
Admin.prototype.constructor = Admin;
return { User, Admin };
}FAQ
Every JavaScript object holds an internal link pointing to a prototype object. Property lookups walk up this chain recursively until they locate a matching property or reach null.
The __proto__ property is a deprecated legacy accessor. The Object.getPrototypeOf() method is the modern, standardized interface. You should use the functional methods in production code.
No, it is not. The class keyword compiles to a standard constructor function. Methods declared in classes sit directly on the constructor's prototype object at runtime.
Shadowing occurs when an object defines a property matching the name of a prototype property. The object's own property overrides the lookup value without altering the prototype itself.
Use the Object.hasOwn(obj, prop) method. This returns true if the property exists directly on the target instance. It returns false for inherited prototype properties.