Sitemap
Aditya Patel

Aditya Patel

I love learning new things

[[Prototype]] vs __proto__ vs .prototype in Javascript

3 min readJan 10, 2026

--

🎯 The Three Concepts

1️⃣ [[Prototype]] (Internal Prototype)

What:

Hidden internal property inside every JavaScript object

Purpose:

The actual mechanism JS uses for inheritance and property lookup

Access:

Cannot access directly in code

obj.[[Prototype]]// ❌ Syntax error

Think of it as:

The real inheritance link

2️⃣ __proto__ (Proto Accessor)

What:

Getter/setter property that exposes [[Prototype]]

Where:

Available on all objects (via Object.prototype)

Status:

⚠️ Deprecated (but widely supported)

obj.__proto__ ===Object.getPrototypeOf(obj)// βœ… true

βœ… Modern alternatives (use these instead):

Object.getPrototypeOf(obj)// Get prototype
Object.setPrototypeOf(obj, proto)// Set prototype
Object.create(proto)// Create with prototype

Think of it as:

Legacy way to view/change [[Prototype]]

3️⃣ .prototype (Prototype Property)

What:

Regular object property that exists only on functions

Purpose:

Blueprint object used when function is called with new

Key point:

NOT the function’s own prototype

functionUser() {}
User.prototype// βœ… exists (it's an object)
const u =newUser();
u.prototype// ❌ undefined (instances don't have it)

Think of it as:

Get Aditya Patel’s stories inΒ yourΒ inbox

Join Medium for free to get updates fromΒ thisΒ writer.

Template for future instances

πŸ”— How They Connect: The new Operator

functionUser(name) {
this.name = name;
}
const u1 =newUser('Alice');

What new does internally:

// Simplified version
1.Create emptyobject:const u1 = {}
2.Linkprototype: u1.[[Prototype]] =User.prototype
3.Callconstructor:User.call(u1,'Alice')
4.Returnobject:return u1

The connection:

u1.__proto__ === User.prototype  // βœ…true

πŸ‘₯ Multiple Instances Share One Prototype

functionUser() {}
User.prototype.sayHi =function() {
console.log('Hi!');
};
const u1 =newUser();
const u2 =newUser();
const u3 =newUser();

Memory structure:

u1.__proto__ ──┐
u2.__proto__ ──┼──→ User.prototype (ONE object in memory)
u3.__proto__ β”€β”€β”˜

βœ… Benefits:

  • Methods defined once
  • Shared across all instances
  • Memory efficient

πŸ” Prototype Lookup Chain

const u1 =newUser();
u1.sayHi();// How does JS find this?

Lookup order:

  1. Check u1 itself β†’ Not found
  2. Check u1.[[Prototype]] (i.e., User.prototype) β†’ Found! βœ…
  3. If not found, check User.prototype.[[Prototype]] β†’ Object.prototype
  4. If still not found, check Object.prototype.[[Prototype]] β†’ null

πŸ†š Function vs Object

Function (Constructor)

functionUser() {}

Has:

  • βœ… .prototype (points to object for instances)
  • βœ… __proto__ (points to Function.prototype)
  • βœ… [[Prototype]] (internal, = Function.prototype)

Why?

Functions can create objects AND are objects themselves.

Regular Object (Instance)

const obj = {};

Has:

  • ❌ .prototype (doesn't exist)
  • βœ… __proto__ (points to Object.prototype)
  • βœ… [[Prototype]] (internal, = Object.prototype)

Why?

Objects are instances, not constructors.

πŸŽ“ Classes = Syntactic Sugar

classUser {
sayHi() {
console.log('Hi');
}
}

Behind the scenes:

// Equivalent to:
functionUser() {}
User.prototype.sayHi =function() {
console.log('Hi');
};

πŸ‘‰ Classes use the same prototype system internally!

πŸ“Š The Complete Picture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚User (function) β”‚
β”‚ .prototype ───────────┐ β”‚
β”‚ __proto__ β†’Function.prototype β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β”‚
↓
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚User.prototype β”‚
β”‚ (object) β”‚
β”‚ -sayHi() β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
↑
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ β”‚ β”‚
β”Œβ”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”
β”‚ u1 β”‚ β”‚ u2 β”‚ β”‚ u3 β”‚
β”‚ __proto__ β”‚ β”‚ __proto__ β”‚ β”‚ __proto__ β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

πŸ”‘ Golden Rules (Memorize These!)

  • .prototype β†’ Property on constructor functions only
  • __proto__ β†’ Accessor on all objects (deprecated, use Object.getPrototypeOf())
  • [[Prototype]] β†’ Internal link used by JS engine
  • All instances share the same prototype object
  • Property lookup travels up the prototype chain

πŸ’‘ Interview One-Liner

[[Prototype]] is the actual inheritance mechanism, __proto__ is a deprecated way to access it, and .prototype is the object that constructor functions give to their instances as their [[Prototype]].

⚠️ Common Mistakes

❌ Wrong:

functionUser() {}
const u =newUser();
u.prototype.sayHi =function() {}// Error! u.prototype is undefined

βœ… Correct:

User.prototype.sayHi =function() {}// Add to constructor's prototype

πŸš€ Quick Reference

Concept Location Purpose Access [[Prototype]] All objects Internal inheritance link Object.getPrototypeOf() __proto__ All objects Legacy accessor Direct (deprecated) .prototype Functions only Template for instances Direct

--

--