JavaScript Prototypal Inheritance
Learn JavaScript prototypal inheritance: the hidden [[Prototype]] link, __proto__ and Object methods, the prototype chain, and property shadowing with examples.
In JavaScript, objects can inherit properties and methods from other objects through a mechanism called prototypal inheritance. Instead of copying features from a class (as in Java or C++), every object holds a hidden link to another object — its prototype — and JavaScript follows that link whenever it can't find a property on the object itself. This page covers how that hidden link works, the difference between __proto__ and Object.getPrototypeOf/setPrototypeOf, how the prototype chain is searched, the role of F.prototype for constructor functions, property shadowing, and how this behaves along the chain.
The hidden [[Prototype]] link
Every JavaScript object has a hidden internal property called [[Prototype]]. It is either null or a reference to another object, and that referenced object is called the object's prototype.
[[Prototype]] is an internal slot in the language specification — you can't read it with a normal property access. Instead you work with it through two public APIs:
- The historical accessor
__proto__(a getter/setter exposed byObject.prototype). - The modern, recommended methods
Object.getPrototypeOf(obj)andObject.setPrototypeOf(obj, proto).
The simplest way to set a prototype is with __proto__ inside an object literal. Here we make animal the prototype of rabbit, so rabbit can read animal's properties:
__proto__ vs Object.getPrototypeOf / setPrototypeOf
__proto__ is a getter/setter that has long been deprecated for general use — it is only standardized for browser compatibility. In real code, prefer the explicit methods:
Note the difference: __proto__ is a property accessor, while getPrototypeOf/setPrototypeOf are functions. Two practical rules:
__proto__is not the same as[[Prototype]].__proto__is just the accessor that reads/writes the internal[[Prototype]]slot.- Avoid changing a prototype after an object is created.
Object.setPrototypeOfand assigningobj.__proto__are slow operations: engines heavily optimize objects whose prototype is fixed at creation time. Set the prototype once, when you build the object.
The prototype chain
The prototype's prototype can have a prototype too, forming a prototype chain. When you read obj.prop, JavaScript:
- Looks for
propas an own property ofobj. - If not found, follows
[[Prototype]]and looks on the prototype. - Repeats step 2 up the chain until it finds
propor reachesnull.
If the chain ends at null without finding the property, the result is undefined.
There are two limits on the chain: references must not form a loop (JavaScript throws if you try to create a cycle), and [[Prototype]] must be either an object or null.
Property shadowing: writing vs reading
The prototype is only consulted for reading. When you write to or delete a property, the operation always acts on the object itself, never on its prototype. Assigning a property that also exists on the prototype creates an own property that shadows (hides) the inherited one:
The exception is accessor properties (getters/setters): because a setter is a function call, writing through an inherited setter runs that setter rather than creating a new own data property.
this is always the calling object
A common source of confusion: no matter where a method lives in the chain, this inside it is the object before the dot when the method was called — never the prototype it was defined on. Inherited methods therefore operate on the inheriting object's own state:
This is what makes shared methods on a prototype useful: one method definition, but each object stores its own data.
Constructor functions and F.prototype
Setting [[Prototype]] by hand for every object is tedious. The classic pattern is a constructor function used with new. Every function has a regular property called prototype (written F.prototype). When you call new F(), the newly created object's [[Prototype]] is set to F.prototype.
Keep F.prototype distinct from an object's [[Prototype]]: F.prototype is an ordinary property of the constructor function that supplies the [[Prototype]] for objects created with new F(). By default F.prototype is an object with a single non-enumerable constructor property pointing back to the function itself.
Note: Modern ES6
classsyntax is syntactic sugar over exactly this mechanism. Aclassdeclaration creates a constructor function, puts its methods onConstructor.prototype, and wires up the chain with the same[[Prototype]]links. See JavaScript Class Inheritance for theextends/superform.
Creating objects with Object.create
Object.create(proto) builds a fresh object with [[Prototype]] set to proto directly — no constructor needed. It is the most explicit way to set up inheritance, and it accepts a second argument: a property-descriptor map, the same format used by Object.defineProperties.
The descriptor map lets you control flags such as writable, enumerable, and configurable — see JavaScript Property Flags and Descriptors for what each flag does. Objects made with Object.create(null) (so-called "very plain" objects) are covered in Prototype Methods, Objects Without __proto__.
Multi-level inheritance
Because each prototype can have its own prototype, you can build chains several levels deep to model more specific relationships:
Inspecting and iterating the chain
To check whether an object is somewhere in another object's chain, use isPrototypeOf. To separate own properties from inherited ones, use hasOwnProperty — note that for...in walks the whole chain (enumerable properties only), while Object.keys returns own keys only.
Built-in types such as arrays, functions, and dates also rely on this chain — their methods live on Array.prototype, Function.prototype, and so on. See JavaScript Native Prototypes for how the built-ins are wired together.
Summary
- Every object has a hidden
[[Prototype]]that is another object ornull. - Read
[[Prototype]]withObject.getPrototypeOf, set it withObject.setPrototypeOf;__proto__is the legacy accessor and changing a prototype after creation is slow. - Reads walk up the prototype chain until the property is found or the chain ends at
null; writes and deletes always act on the object itself and can shadow inherited properties. thisinside a method is the object the method was called on, not the prototype where it was defined.new F()sets the new object's[[Prototype]]toF.prototype; ES6classis syntactic sugar over this exact mechanism — see JavaScript Class Inheritance.