JS Foundations #4 — Prototypes & Inheritance

Understand __proto__ vs prototype, the prototype chain, what new actually does, and how class extends desugars to prototypes.

11 min read
JavaScript
Fundamentals
Prototypes

TABLE OF CONTENTS
JS Foundations #4 — Prototypes & Inheritance

JavaScript uses prototypal inheritance, not classical inheritance. Every object has an internal [[Prototype]] link to another object.

Think of prototypes like looking up a word in a family of dictionaries. You first check your own dictionary (the object itself). If the word isn't there, you check your parent's dictionary. Then your grandparent's. You keep going up the chain until you find the definition — or run out of dictionaries. This is exactly how property lookup works in JavaScript.

Understanding this chain — and the difference between __proto__ and prototype — is the key to understanding how properties are looked up, how new works, and what class actually does.

Prerequisites: JS Foundations #3 — Closures


1. __proto__ vs prototype — The Most Confused Concept

There are two different things that sound similar:

  • __proto__ (or [[Prototype]]): exists on every object — it's the link to the object it inherits from
  • prototype: exists only on functions — it's the object that becomes the __proto__ of instances created by new

Loading editor...

The mental model:

naveen  ──.__proto__──→  Person.prototype  ──.__proto__──→  Object.prototype  ──.__proto__──→  null
  { name: "Naveen" }      { greet: fn }                      { hasOwnProperty, toString, ... }

2. The Prototype Chain — How Property Lookup Works

When you access obj.prop, the engine:

  1. Looks on obj itself
  2. If not found, looks on obj.__proto__
  3. If not found, looks on obj.__proto__.__proto__
  4. Continues until it reaches null — then returns undefined

Loading editor...


3. Setting Properties on the Prototype

Properties on the prototype are shared across all instances. Mutating a reference type on the prototype affects everyone:

Loading editor...


4. What new Actually Does (Step by Step)

Loading editor...


5. Constructor Property

Every prototype object has a .constructor property pointing back to the function:

Loading editor...

This is easily broken if you overwrite prototype entirely:

Loading editor...


6. Inheritance Without Classes

Before class extends, we built inheritance chains manually:

Loading editor...

The prototype chain we built:

rex  ──→  Dog.prototype  ──→  Animal.prototype  ──→  Object.prototype  ──→  null

7. Object.create() — The Purest Form of Prototypal Inheritance

You can create an object that inherits from another without any constructor function:

Loading editor...


8. instanceof — Checking the Prototype Chain

obj instanceof Constructor walks obj.__proto__ up the chain and checks if it ever equals Constructor.prototype:

Loading editor...


9. for...in vs hasOwnProperty — Why It Matters

for...in loops over all enumerable properties, including inherited ones. Use hasOwnProperty to filter them out:

Loading editor...

Always guard for...in with hasOwnProperty unless you specifically want inherited properties.


10. Object.create(null) — An Object with No Prototype

Sometimes you want a plain dictionary without any inherited baggage (no toString, hasOwnProperty, etc.):

Loading editor...

This is useful for lookup maps where keys might collide with built-in method names (like toString, constructor, __proto__).


11. class — Syntax Sugar Over Prototypes

Modern class syntax does the same thing under the hood:

Loading editor...


Key Takeaways

ConceptMeaning
__proto__ / [[Prototype]]The link from an object to its parent — exists on EVERY object
prototypeThe object that becomes __proto__ for new instances — exists only on FUNCTIONS
newCreates object, links __proto__, calls constructor, returns object
Object.create(proto)Pure prototypal inheritance — no constructor needed
instanceofWalks __proto__ chain checking against Constructor.prototype
class extendsSyntax sugar — builds the same __proto__ chain underneath
  • Properties are looked up by walking the __proto__ chain until found or null.
  • Don't put mutable reference types (arrays, objects) on prototype — they are shared.
  • Object.create(null) creates an object with no prototype — useful for dictionaries.

Next: JS Foundations #5 — Equality & Type Coercion== vs ===, the abstract equality algorithm, and why [] == ![] is true.


Let's Connect

© 2026 Naveen Karthik // Built with React & MUI