skip to content

In JavaScript, what is the difference between a function's `.prototype` property and an object's `__proto__`?

level: juniorimportance: must knowfreq 85%

answer

  1. one belongs to functions only
  2. the other is every object's link
  3. given at creation vs already held
  4. new sets instance link from F.prototype
  5. Object.getPrototypeOf(d) === Dog.prototype

basics

~20 s

A function's .prototype is an ordinary property holding the object that instances created from that function will delegate to. An object's proto is that object's own delegation link, the object it actually inherits from right now.

solid answer

~40 s

They name two different things. Every object has an internal `[[Prototype]]` slot — a link to another object or to `null` — and that link is what property lookup follows; `__proto__` is a legacy accessor exposing it, and `Object.getPrototypeOf(obj)` is the modern way to read it. `.prototype` is not that link: it is a plain, visible property that only functions carry, holding the object that becomes the `[[Prototype]]` of objects the function creates with `new`. So for `function Dog(){}` and `const d = new Dog()`, `Object.getPrototypeOf(d) === Dog.prototype` is true, while `d.prototype` is `undefined` because `d` is not a function. The function itself also has its own link — `Object.getPrototypeOf(Dog) === Function.prototype` — which is a completely different object from `Dog.prototype`.

code

javascript · 13 lines
javascript
function Dog(name) {
  this.name = name;
}
Dog.prototype.speak = function () {
  return this.name + ' barks';
};

const d = new Dog('Rex');

console.log(Object.getPrototypeOf(d) === Dog.prototype); // true
console.log(d.prototype);                                // undefined
console.log(Object.getPrototypeOf(Dog) === Function.prototype); // true
console.log(Dog.prototype === Function.prototype);       // false

go deeper

for a junior

Be able to state plainly that only functions have a .prototype property, that it holds the object future instances will inherit from, and that an ordinary object's own link is read with Object.getPrototypeOf.

for a middle

Explain the mechanics: the engine auto-creates .prototype with a constructor back-pointer, new copies that reference into the instance's [[Prototype]] slot, and the function's own link points at Function.prototype.

for a senior

Show you can debug with this — trace why a method vanished after someone reassigned .prototype, or why instances created before and after a change behave differently, and know the shared-method memory argument.

for a principal

Frame the tradeoff for a codebase: prototype-shared methods versus per-instance closures affects memory and engine shape optimisation, and public .prototype mutation is an unguarded extension point library consumers can and will abuse.

## Two names, two different things Every JavaScript object carries an internal slot the specification writes as `[[Prototype]]`. It holds either another object or `null`, and it is the link the engine follows when a property is not found on the object itself. You read it with `Object.getPrototypeOf(obj)`; `obj.__proto__` is an older accessor that reaches the same slot. `.prototype` is something else entirely: an ordinary, visible property that lives on **functions**, not on ordinary objects. It holds a plain object that the function hands out. When the function is called with `new`, the newly created object's `[[Prototype]]` is set to whatever `F.prototype` references at that moment. The one-line version: `.prototype` is what a function **gives** to the objects it creates; `[[Prototype]]`/`__proto__` is what an object **has**. ```js function Dog(name) { this.name = name; } Dog.prototype.speak = function () { return this.name + ' barks'; }; const d = new Dog('Rex'); Object.getPrototypeOf(d) === Dog.prototype; // true d.speak(); // 'Rex barks' d.prototype; // undefined — d is not a function ``` ## The function has both, and they are unrelated objects `Dog` is itself an object, so it has its own `[[Prototype]]` link — and because it is a function, that link points at `Function.prototype`. Separately, it owns a `.prototype` property pointing at the object `d` delegates to. These are two different objects that happen to hang off the same function: ```js Object.getPrototypeOf(Dog) === Function.prototype; // true — Dog's own link Dog.prototype === Function.prototype; // false — the instance prototype ``` Mixing these two up is the classic mistake. `Dog.__proto__` answers "what does the function `Dog` inherit from?" (methods like `call`, `apply`, `bind`). `Dog.prototype` answers "what will `new Dog()` inherit from?" (`speak`). ## What `.prototype` starts out as For a normal function declaration or expression, the engine creates the `.prototype` object for you: a fresh plain object whose own `constructor` property points back at the function, and whose own `[[Prototype]]` is `Object.prototype`. The property is writable but non-enumerable and non-configurable, which is why you can assign to it and why it never shows up in a `for...in` over the function. ```js function Dog() {} Dog.prototype.constructor === Dog; // true Object.getPrototypeOf(Dog.prototype) === Object.prototype; // true ``` Because instances share that one object, methods put on `.prototype` exist once in memory regardless of how many instances you create — the reason prototype methods are preferred over assigning a fresh function to `this.speak` in the constructor body. ## Reassigning `.prototype` later `.prototype` is read at creation time, and the resulting link is a snapshot. Replacing the function's `.prototype` afterwards does not retroactively change objects that already exist: ```js function Dog() {} const before = new Dog(); Dog.prototype = { speak: () => 'new proto' }; const after = new Dog(); Object.getPrototypeOf(before) === Dog.prototype; // false — kept the old object Object.getPrototypeOf(after) === Dog.prototype; // true ``` *Mutating* the existing `.prototype` object (`Dog.prototype.speak = ...`) is different — every instance already points at that object, so all of them see the change immediately. ## Where classes fit `class C {}` produces exactly the same arrangement: `C` is a function, `C.prototype` holds the instance methods, and `new C()` links the instance to `C.prototype`. The difference is that a class's `.prototype` property is non-writable, so you cannot reassign it wholesale. ## What to say and what to write In conversation, say `[[Prototype]]` or "the object's prototype link" for what an object has, and "the function's `.prototype` property" for what a function exposes. In code, prefer `Object.getPrototypeOf(obj)` over `obj.__proto__`: the former is a plain core-spec function that works on any object, while `__proto__` is a legacy accessor that only exists because the object inherits it from `Object.prototype`.

  • If a function's `.prototype` is just a property, what happens to objects already created when you replace it with a brand-new object?
    Nothing. The link was copied into each instance's `[[Prototype]]` slot when it was created, so existing objects keep pointing at the old prototype object and never see the replacement. Only objects created after the reassignment get the new one. Mutating the existing prototype object in place is different — every instance already references it, so all of them observe the change at once.
  • What does `Object.getPrototypeOf(Dog)` return for a plain function declaration `Dog`, and why is that not `Dog.prototype`?
    `Function.prototype`. `Dog` is itself an object, and every function inherits from `Function.prototype`, which is where `call`, `apply` and `bind` live. `Dog.prototype` is an unrelated plain object created for `Dog`'s future instances; its own prototype is `Object.prototype`. One answers what the function inherits, the other what its instances will inherit.
  • Why put methods on `.prototype` rather than assigning them inside the constructor body?
    A method on `.prototype` exists once and is shared by every instance through the prototype link, so a thousand instances cost one function object. Assigning `this.speak = function(){}` in the constructor creates a fresh closure per instance, multiplying memory and defeating the engine's shared-shape optimisations. Per-instance assignment is only justified when the function must capture constructor-local state.

saying these in an interview costs you the question

  • Says every object has a .prototype property
  • Calls __proto__ and .prototype the same thing
  • Thinks d.prototype reaches the instance's methods
  • Believes Dog.__proto__ equals Dog.prototype
  • Assumes replacing .prototype updates existing instances

context