JavaScript __proto__ vs prototype: What Is the Difference?
Understand the fundamental difference between __proto__ and prototype in JavaScript. Learn what each one is, when each exists, how they connect via the new operator, and why mixing them up causes subtle bugs.
__proto__ and prototype are two of the most consistently confused concepts in JavaScript. They sound similar and relate to the same prototype chain mechanism, but they exist on different types of objects, serve different purposes, and are accessed differently. This guide separates them completely with clear definitions, diagrams, and code examples.
The One-Line Definitions
prototype— A property on function objects (specifically constructor functions and classes). It is the object that will become the[[Prototype]]of any instance created by calling that function withnew.__proto__— The actual[[Prototype]]link on any object instance. It points to the prototype object the instance currently inherits from.
Put simply:
prototypeis the blueprint provider — it lives on the constructor__proto__is the live link — it lives on the instance, pointing up the chain
Visualizing the Relationship
[Function: Animal]
|
Animal.prototype ← (this is where methods live)
/ \
[dog instance] [cat instance]
dog.__proto__ ──────────────┘
cat.__proto__ ──────────────┘When you call new Animal(), the new object's __proto__ is set to Animal.prototype. Both dog and cat share the same prototype object — they copy nothing, they link.
Code Demonstration
function Animal(name) {
this.name = name; // Own property — on the instance
}
// Adding to Animal.prototype — available to all instances via chain
Animal.prototype.breathe = function () {
return `${this.name} breathes`;
};
const dog = new Animal("Rex");
const cat = new Animal("Whiskers");
// PROTOTYPE: the property on the constructor function
console.log(typeof Animal.prototype); // "object"
console.log(Animal.prototype.breathe); // [Function: breathe]
// __proto__: the link on each instance
console.log(dog.__proto__ === Animal.prototype); // true — same object!
console.log(cat.__proto__ === Animal.prototype); // true — same object, shared!
// They point to the SAME prototype object:
console.log(dog.__proto__ === cat.__proto__); // true
// Modifying Animal.prototype affects ALL instances:
Animal.prototype.speak = function () {
return `${this.name} makes a sound`;
};
console.log(dog.speak()); // "Rex makes a sound" — picked up immediately
console.log(cat.speak()); // "Whiskers makes a sound"What the new Operator Does
Understanding new clarifies the relationship:
function Animal(name) {
this.name = name;
}
Animal.prototype.breathe = function () { return "breathing"; };
// new Animal("Rex") does this, roughly:
function simulateNew(Constructor, ...args) {
// 1. Create a new object
const instance = {};
// 2. Set its [[Prototype]] to Constructor.prototype
Object.setPrototypeOf(instance, Constructor.prototype);
// This is what makes instance.__proto__ === Animal.prototype
// 3. Call the constructor with this = instance
const result = Constructor.apply(instance, args);
// 4. Return the instance (or the constructor's return value if it's an object)
return (typeof result === "object" && result !== null) ? result : instance;
}
const dog = simulateNew(Animal, "Rex");
console.log(dog.breathe()); // "breathing" — works exactly like new Animalprototype Only Exists on Functions
Plain objects and instances do not have a prototype property (unless you add one manually):
const obj = {};
console.log(obj.prototype); // undefined — plain objects don't have .prototype
function fn() {}
console.log(fn.prototype); // {} — functions DO have .prototype
const arr = [1, 2, 3];
console.log(arr.prototype); // undefined — arrays are instances, not constructors
console.log(Array.prototype); // [...] — Array is a constructor functionproto — Deprecated but Still Widely Used
__proto__ is technically deprecated. The preferred API is:
| Operation | Legacy (proto) | Modern API |
|---|---|---|
| Get prototype of obj | obj.__proto__ | Object.getPrototypeOf(obj) |
| Set prototype of obj | obj.__proto__ = proto | Object.setPrototypeOf(obj, proto) |
| Create with prototype | N/A | Object.create(proto) |
const proto = { greet() { return "hello"; } };
const obj = Object.create(proto);
console.log(Object.getPrototypeOf(obj) === proto); // true
console.log(obj.__proto__ === proto); // true — same thing, different syntax__proto__ is standardized in Annex B of the spec (for web compatibility) and works everywhere, but Object.getPrototypeOf is the preferred way to read it.
The constructor Property
Every Function.prototype object also has a constructor property pointing back to the function:
function Dog(name) { this.name = name; }
console.log(Dog.prototype.constructor === Dog); // true — points back to Dog
console.log(Dog.prototype.constructor.name); // "Dog"
const rex = new Dog("Rex");
console.log(rex.constructor === Dog); // true — via prototype chain
// rex doesn't have own property "constructor", inherits from Dog.prototypeThis constructor property can break if you replace prototype entirely:
// Replacing prototype breaks constructor
Dog.prototype = {
bark() { return "woof"; },
};
// Dog.prototype.constructor is now Object (the {} literal's constructor)
const rex = new Dog("Rex");
console.log(rex.constructor === Dog); // false — broken!
console.log(rex.constructor === Object); // true — wrong!
// Fix: restore constructor
Dog.prototype = {
constructor: Dog, // Manually restore
bark() { return "woof"; },
};class Syntax and the Same Relationship
class syntax creates the exact same prototype/__proto__ relationships:
class Animal {
constructor(name) { this.name = name; }
breathe() { return `${this.name} breathes`; }
}
class Dog extends Animal {
bark() { return `${this.name} barks`; }
}
const rex = new Dog("Rex");
// Same structure as function constructors:
console.log(rex.__proto__ === Dog.prototype); // true
console.log(Dog.prototype.__proto__ === Animal.prototype); // true
console.log(Animal.prototype.__proto__ === Object.prototype); // true
// Methods live on the prototype objects:
console.log(Dog.prototype.hasOwnProperty("bark")); // true
console.log(Animal.prototype.hasOwnProperty("breathe")); // true
console.log(rex.hasOwnProperty("bark")); // false — it's on Dog.prototypeQuick Reference Diagram
new Dog("Rex")
|
v
rex (instance)
|
rex.__proto__ ────────────→ Dog.prototype
|
Dog.prototype.__proto__ ──────→ Animal.prototype
|
Animal.prototype.__proto__ ──→ Object.prototype
|
Object.prototype.__proto__ → nullRune AI
Key Insights
- prototype lives on constructor functions: It is the object assigned as [[Prototype]] to each instance created with new — it is NOT a property that instances have (usually)
- proto lives on instances: It is the actual [[Prototype]] link pointing to the object that was the constructor's prototype at creation time
- new connects them: The first thing new does is create an object with [[Prototype]] = Constructor.prototype, establishing the inheritance link
- Both point to the same object: dog.proto === Animal.prototype is always true for correctly-constructed instances — they are not copies, they are the same reference
- Use Object.getPrototypeOf for modern code: proto works everywhere but is deprecated as a direct property access pattern; Object.getPrototypeOf(obj) is the standardized API
Frequently Asked Questions
Can I safely use __proto__ in production code?
Does every function have a prototype property?
What happens if __proto__ and prototype point to different objects?
Is there a performance penalty for long prototype chains?
How is proto different from [[Prototype]]?
Conclusion
prototype is a property on constructor functions — it provides the shared methods that new-created instances will inherit. __proto__ is the live [[Prototype]] link on each instance — it points to that shared prototype object. The new operator connects them: the instance's __proto__ is set to the constructor's prototype. Understanding this connection is the key to understanding the prototype chain, instanceof, method sharing, and how class extends works at the runtime level.
More in this topic
OffscreenCanvas API in JS for UI Performance
Master the OffscreenCanvas API to offload rendering from the main thread. Covers worker-based 2D and WebGL rendering, animation loops inside workers, bitmap transfer, double buffering, chart rendering pipelines, image processing, and performance measurement strategies.
Advanced Web Workers for High Performance JS
Master Web Workers for truly parallel JavaScript execution. Covers dedicated and shared workers, structured cloning, transferable objects, SharedArrayBuffer with Atomics, worker pools, task scheduling, Comlink RPC patterns, module workers, and performance profiling strategies.
JavaScript Macros and Abstract Code Generation
Master JavaScript code generation techniques for compile-time and runtime metaprogramming. Covers AST manipulation, Babel plugin authorship, tagged template literals as macros, code generation pipelines, source-to-source transformation, compile-time evaluation, and safe eval alternatives.