Understand the prototype chain, Object.create, and how class syntax wraps prototypal inheritance.
Object.create method.class declarations as syntactic sugar over prototype chains.Object.getPrototypeOf() method instead of legacy properties like __proto__ to inspect prototypes.Object.hasOwn() before accessing inherited properties.Object.setPrototypeOf because it degrades property access performance.for...in loops to prevent iteration leaks from inherited enumerable method names.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); // nullObject.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 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 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() + "!"; }
}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"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.
Compiling Class Inheritance to Prototypes
Demonstrates how modern ES6 classes are transformed into prototype constructors under the hood.
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 };
}Class declarations compile to constructor functions with shared methods placed on their prototype chains.