Prototypal inheritance is a core JavaScript mechanism where objects can directly inherit properties and methods from other objects through a linked chain, rather than from classes as in classical object-oriented languages.
In JavaScript, every object has an internal link to another object called its prototype. When you access a property on an object, the engine first checks the object itself, then walks up this chain of prototypes until it finds the property or reaches null. This chain is often called the prototype chain. Unlike classical inheritance, no copying of properties occurs — objects simply delegate lookups to their prototype.
Prototypal inheritance allows efficient memory use because methods defined on a prototype are shared across all inheriting objects rather than duplicated on each instance. It enables highly flexible object composition and runtime extension of behavior. Understanding it is essential for debugging JavaScript, working with frameworks, and writing performant code.
Every function in JavaScript has a prototype property, which is a plain object. When you use the new keyword to create an instance, the engine sets the instance's internal [[Prototype]] slot to point at that function's prototype object. You can inspect or set this link using Object.getPrototypeOf() and Object.create(). The modern class syntax in ES6 is syntactic sugar that still uses this same prototype mechanism.
Object.create(proto) directly creates a new object with proto as its prototype, giving you the most explicit control over the chain. The new keyword automates wiring up the prototype and calling a constructor function. ES6 class syntax wraps both concerns in familiar class/extends keywords but compiles down to the same prototype linkage. All three approaches produce the same underlying prototype chain.
Because all instances share the same prototype object, mutable reference types like arrays or objects defined on the prototype are shared across every instance. Mutating such a property on one instance will appear to affect all others. The best practice is to define only methods on the prototype and initialize instance-specific data inside the constructor function or class constructor so each instance gets its own copy.
Use obj.hasOwnProperty(key) or Object.hasOwn(obj, key) to distinguish between properties defined directly on an object and those inherited through the prototype chain. A standard for...in loop iterates over both own and inherited enumerable properties, which can cause subtle bugs. Prefer Object.keys() when you need only the object's own enumerable properties to keep your code predictable and safe.
© RM Full Stack & AI Engineer · All guides · Roadmaps · Open the app