Prototypes
Introduction
Every ordinary JavaScript object has an internal [[Prototype]] reference to another object or to null. That reference is what powers inherited property lookup.
Do not confuse an object's internal [[Prototype]] with a function's .prototype property. They are related by new, but they are not the same concept.
Why This Matters
Prototype confusion is one of the highest-signal JavaScript interview areas. If you can distinguish obj.[[Prototype]], Constructor.prototype, and legacy __proto__, you can explain new, methods on class instances, instanceof, and inheritance without memorising snippets.
Theory
The internal [[Prototype]]
An object's [[Prototype]] is an internal link used when a property is not found directly on the object. You inspect it with Object.getPrototypeOf(obj) and can change it with Object.setPrototypeOf(obj, proto), although changing prototypes of existing objects is usually bad for performance and clarity.
The .prototype property on functions
Most normal functions have a .prototype object. When you call a function with new, JavaScript creates a new object whose [[Prototype]] points to that function's .prototype. That is why methods assigned to User.prototype are shared by all instances created with new User().
__proto__
__proto__ is a legacy accessor on Object.prototype that exposes an object's internal prototype in many environments. Prefer Object.getPrototypeOf and Object.setPrototypeOf in teaching and production code because they are explicit and work better with unusual objects.
Constructors and shared methods
Putting methods on the prototype avoids creating a new function per instance. Each instance stores its own data, while methods are shared through the prototype.
Arrow functions and .prototype
Arrow functions cannot be used as constructors and do not have a useful .prototype for new. This is one reason constructor functions, method shorthand, and classes have different roles in the language.
Visual Diagrams
function User(name) { ... }
User --------------------------+
| prototype ----------------+ |
+---------------------------|--+
v
User.prototype
+--------------------+
| greet: function |
| constructor: User |
+--------------------+
^
|
new User('Ada') |
instance.[[Prototype]] --------+`User.prototype` becomes the `[[Prototype]]` of objects created with `new User()`.
Code Examples
Methods shared through a constructor prototype
Each instance owns name; the greet method is shared on User.prototype.
Prefer Object.getPrototypeOf over __proto__
__proto__ is widely available but legacy. The standard explicit API is clearer.
Playground
Press Run to execute the code and see output here.
Output Prediction
Predict the output #1
1function Box(value) {2 this.value = value;3}4 5Box.prototype.get = function () {6 return this.value;7};8 9const box = new Box(7);10 11console.log(box.get());12console.log(box.hasOwnProperty('get'));13console.log(Object.getPrototypeOf(box) === Box.prototype);Predict the output #2
1const proto = { shared: true };2const obj = { own: true };3 4Object.setPrototypeOf(obj, proto);5 6console.log(obj.shared);7console.log(obj.__proto__ === proto);8console.log(Object.getPrototypeOf(obj) === proto);Coding Exercises
Create a constructor with a shared method
MediumImplement a Counter constructor. Each instance should own its count, and all instances should share an increment() method through Counter.prototype.
Interview Questions
1What is the difference between `[[Prototype]]` and `.prototype`?
[[Prototype]] is an internal link every ordinary object has to another object or null. A function's .prototype is a normal property used by new: instances created with new Fn() get their [[Prototype]] set to Fn.prototype.
Follow-ups
- How does `new` use `.prototype`?
- Why do arrow functions not work with `new`?
2Should you use `__proto__`?
For interviews, know that __proto__ is a legacy accessor exposing the internal prototype on many objects. In production and explanations, prefer Object.getPrototypeOf and Object.setPrototypeOf because they are explicit standard APIs. Avoid changing prototypes of existing hot objects unless you have a strong reason.
Quiz
1. When `const x = new User()`, what is usually true?
2. Which API is preferred for reading an object's internal prototype?
Summary
- An object's internal `[[Prototype]]` is the next object searched during property lookup.
- A constructor function's `.prototype` becomes the `[[Prototype]]` of instances created with `new`.
- `__proto__` is legacy; prefer `Object.getPrototypeOf` and `Object.setPrototypeOf`.
- Prototype methods are shared, while instance data is usually owned by each instance.
Cheat Sheet
Internal link: Object.getPrototypeOf(obj) reads obj.[[Prototype]].
Constructor property: Fn.prototype is used by new Fn().
Legacy: obj.__proto__ often exposes the same link but should not be your default API.
Shared method: Fn.prototype.method = function () { ... }
Instance check: Object.getPrototypeOf(instance) === Fn.prototype.