Every JavaScript object has an internal [[Prototype]] link forming a chain — property lookups walk this chain until found or null. ES6 classes are syntactic sugar over this prototypal inheritance model.
Every object has a [[Prototype]] link. Property lookups walk the chain from the object through its prototypes until found or null is reached.
When called with new, instances inherit from the constructor's .prototype property. Methods placed on .prototype are shared across all instances.
Creates an object with a specified prototype — the most direct way to set up inheritance chains. Object.create(null) creates a prototype-free object.
Classes provide cleaner syntax but use the same prototype mechanism. extends sets up the chain, super calls parent constructors and methods.
hasOwnProperty() checks own properties only; the in operator checks the full chain. Object.keys() returns own enumerable properties.
JavaScript uses prototypal inheritance rather than classical (class-based) inheritance. Every object has a hidden link to another object called its prototype, forming a chain that the engine traverses when looking up properties. Understanding this mechanism is essential because ES6 classes are syntactic sugar over it — not a replacement.
Every JavaScript object has an internal [[Prototype]] slot (accessible via Object.getPrototypeOf(obj), not directly). When you access a property on an object, the engine first checks the object's own properties. If not found, it follows the [[Prototype]] link to the prototype object and checks there. This continues up the chain until the property is found or the chain ends at null.
The top of most prototype chains is Object.prototype, which provides methods like toString(), hasOwnProperty(), and valueOf(). Its prototype is null, ending the chain.
When you call a function with new, JavaScript: (1) creates a new empty object, (2) sets its [[Prototype]] to the constructor's .prototype property, (3) executes the constructor with this bound to the new object, and (4) returns the object. The .prototype property on constructor functions is the template that all instances created with new inherit from.
function Dog(name) { this.name = name; }
Dog.prototype.bark = function() { return 'Woof!'; };
const rex = new Dog('Rex');
rex.bark(); // 'Woof!' — found on Dog.prototyperex has its own name property, but bark is found on Dog.prototype via the chain.
Object.create(proto) creates a new object with its [[Prototype]] set to proto. This is the most direct way to set up prototype chains without constructors: const child = Object.create(parent) makes child inherit from parent. Object.create(null) creates an object with no prototype — no inherited methods at all, useful for pure dictionary objects.
Classes provide cleaner syntax for constructor functions and prototypal inheritance. class Dog { constructor(name) { this.name = name; } bark() { return 'Woof!'; } } is equivalent to the constructor function pattern above. Methods defined in the class body are placed on the prototype, not on each instance.
extends sets up the prototype chain: class Puppy extends Dog makes Puppy.prototype.[[Prototype]] point to Dog.prototype. super() calls the parent constructor. super.method() calls a parent method. Static methods are inherited through the constructor chain.
Classes are not hoisted like function declarations — they exist in the Temporal Dead Zone like let/const.
obj.hasOwnProperty('key') returns true only for properties directly on the object, not inherited ones. The in operator checks the entire prototype chain. Object.keys() returns only own enumerable properties. for...in iterates own and inherited enumerable properties — use hasOwnProperty to filter.
__proto__ was an unofficial way to access an object's prototype. It's standardized for backward compatibility but deprecated. Use Object.getPrototypeOf() to read and Object.setPrototypeOf() to write (though changing an object's prototype after creation is a performance anti-pattern).
JavaScript doesn't have classical inheritance — it has delegation through the prototype chain. When a property isn't found on an object, the lookup delegates to its prototype. ES6 classes don't change this mechanism — they are syntactic sugar that makes prototypal inheritance look like classical syntax. Understanding the prototype chain is necessary to debug inheritance issues and understand how methods are shared across instances.
Fun Fact
JavaScript's prototypal inheritance was inspired by the Self programming language (1987), where objects inherit directly from other objects without classes. Brendan Eich originally wanted to implement Self-style prototypes, but Netscape management insisted on Java-like syntax — so he added the new keyword and constructor functions as a compromise, creating the unique hybrid system we have today.