Two similarly named things do completely different jobs, and mixing them up is the single most common confusion in the whole topic.
Complete lesson & earn 250 PX
EXERCISE
1The property named prototype does not belong to ordinary objects at all, which is the first thing to fix.
EXERCISE
2Where you put a method decides whether every instance gets its own copy or they all share one, and the difference is measurable.
EXERCISE
3Once both words are clear, the standard chain diagram becomes something you can derive rather than memorise.
There are two things in JavaScript with confusingly similar names, and essentially everyone who learns this topic loses a day to the confusion. Getting them apart now saves you that day.
The two are __proto__ and .prototype. Said out loud they sound like variants of the same idea. They are not related in the way the names suggest, they live on different kinds of value, and they do different jobs.
Start by checking who even has each one:
const user = { name: "Ada" };
function Person(name) {
this.name = name;
}
console.log(user.prototype); // undefined
console.log(Person.prototype); // { constructor: Person }
console.log(user.__proto__); // Object.prototype
console.log(Person.__proto__); // Function.prototype
Read the first pair again. A plain object does not have a property called prototype. Only functions do. If you have been picturing prototype as something every object carries around, that picture is the source of the confusion and this is the moment to drop it.
The second pair shows that both of them do have __proto__, because a function is an object too, and every object has the internal link from the previous lesson.
So, the two definitions, stated once and precisely:
// __proto__ The link THIS object follows when a property lookup fails.
// Every object has one. Read it with Object.getPrototypeOf.
// It is the thing the previous lesson was about.
// .prototype A property that only FUNCTIONS have. It holds an object.
// That object is what instances built by this function
// will use as THEIR __proto__.
// It is NOT the function's own prototype link.
That last line is the one to memorise. Person.prototype is not Person's prototype. Person's prototype is Function.prototype. Person.prototype is the object that Person hands out to everything it constructs.
The naming really is that bad. It was chosen in 1995 and cannot be changed now without breaking the web, so every developer alive has had to learn it as an exception rather than as something that makes sense.
And here is the single line where the two connect:
function Person(name) {
this.name = name;
}
Person.prototype.greet = function () {
return `Hi, ${this.name}`;
};
const ada = new Person("Ada");
console.log(ada.__proto__ === Person.prototype); // true
console.log(ada.greet()); // Hi, Ada
When new ran, it took the object held in Person.prototype and installed it as ada.__proto__. That is the entire relationship. One is the blueprint a constructor holds; the other is the link an instance ends up with. new is what copies one into the other, and lesson 4 takes that apart step by step.
Once that click happens, ada.greet() stops being mysterious. greet is not on ada. The lookup failed on ada, followed ada.__proto__ to Person.prototype, found greet there, and called it with this still pointing at ada.
Pro Tip: A phrasing that survives contact with real code:
.prototypeis the blueprint a constructor hands out,__proto__is the link an instance actually holds. If you ever find yourself writingsomeObject.prototypeand gettingundefined, you have reached for the constructor's property on an instance, which is the single most common mistake in this topic and now one you can recognise instantly.
You now know that a constructor hands its .prototype object to everything it builds. The practical question is what you should put in there, and the answer turns out to matter for both memory and correctness.
There are two places a method can go. Inside the constructor body, assigned to this. Or on the constructor's .prototype. They look almost identical at the call site and behave very differently underneath.
Defined inside the constructor, every instance gets its own copy:
function Person(name) {
this.name = name;
this.greet = function () {
return `Hi, ${this.name}`;
};
}
const a = new Person("Ada");
const b = new Person("Bob");
console.log(a.greet === b.greet); // false
console.log(a.hasOwnProperty("greet")); // true
false is the important line. These are two separate function objects that happen to contain identical code. Every call to new Person builds another one. If your application holds ten thousand people in memory, it is holding ten thousand copies of a function that does exactly the same thing each time.
Defined on .prototype, they share a single function:
function Person(name) {
this.name = name;
}
Person.prototype.greet = function () {
return `Hi, ${this.name}`;
};
const a = new Person("Ada");
const b = new Person("Bob");
console.log(a.greet === b.greet); // true
console.log(a.hasOwnProperty("greet")); // false
console.log(a.greet(), b.greet()); // Hi, Ada Hi, Bob
Same output per person, one function object in total. And the reason each person still gets their own name in the greeting is the rule from lesson 1: the method was found on the prototype, but this is whatever sat to the left of the dot. Shared code, per-object data, no conflict.
So the division of labour is simple and worth stating plainly:
function Person(name, age) {
// PER-INSTANCE DATA goes in the constructor.
// These differ from one person to the next.
this.name = name;
this.age = age;
}
// SHARED BEHAVIOUR goes on the prototype.
// These are identical for every person, so one copy will do.
Person.prototype.greet = function () {
return `Hi, ${this.name}`;
};
Person.prototype.isAdult = function () {
return this.age >= 18;
};
If a thing varies between instances it belongs to the instance. If it is the same logic for all of them it belongs on the prototype. That is the whole rule, and it is exactly the rule class will apply for you in Unit 3.
One sharp edge, because you will hit it in older code:
function Person(name) {
this.name = name;
}
Person.prototype = {
greet() {
return "hi";
},
}; // replaced, not extended
const p = new Person("Ada");
console.log(p.constructor === Person); // false
console.log(p.constructor === Object); // true
Assigning a fresh object literal to .prototype throws away the original, and the original carried a constructor property pointing back at Person. The replacement is a plain literal, so constructor now resolves further up the chain to Object. Anything relying on p.constructor is quietly wrong from that point on. Add to the prototype rather than replacing it, or put constructor back deliberately.
Pro Tip: This split is not an old-fashioned style you will abandon once you learn
class. It is precisely whatclasscompiles to, which is why a class body holds methods while theconstructorholds assignments tothis. Understanding it here means Unit 3 is a syntax lesson rather than a second concept to learn.
Every explanation of this topic eventually shows you a box-and-arrow diagram, and most people nod at it without being able to reproduce it. Now that __proto__ and .prototype are separated, you can derive the whole thing from two facts instead of remembering it.
The two facts: every object has a __proto__ pointing at the next object up, and new sets an instance's __proto__ to the constructor's .prototype.
The full picture for one instance:
function Person(name) {
this.name = name;
}
Person.prototype.greet = function () {
return "hi";
};
const ada = new Person("Ada");
// ada --__proto__--> Person.prototype --__proto__--> Object.prototype --> null
console.log(ada.__proto__ === Person.prototype); // true
console.log(Person.prototype.__proto__ === Object.prototype); // true
console.log(Object.prototype.__proto__); // null
Three objects and a terminus. ada holds the data. Person.prototype holds the shared methods. Object.prototype holds what every object gets. Then null, and any lookup that got this far returns undefined.
There is also a link pointing back down, which is where constructor comes from:
console.log(Person.prototype.constructor === Person); // true
console.log(ada.constructor === Person); // true
console.log(ada.hasOwnProperty("constructor")); // false
ada does not own a constructor property. Person.prototype does, it was put there automatically when the function was declared, and ada finds it by the usual lookup. This is how code can ask an object what built it, and it is also why replacing .prototype wholesale in the previous exercise broke that question.
Now the payoff: the built-in types follow the identical shape:
const nums = [1, 2, 3];
console.log(nums.__proto__ === Array.prototype); // true
console.log(Array.prototype.__proto__ === Object.prototype); // true
console.log(nums.constructor === Array); // true
const fn = function () {};
console.log(fn.__proto__ === Function.prototype); // true
console.log(Function.prototype.__proto__ === Object.prototype); // true
Arrays are not a special construct bolted onto the language alongside objects. An array is an object whose chain happens to pass through Array.prototype, which is the object where map, filter and the rest are defined.
This is the moment the topic becomes useful rather than academic. You do not need a separate mental model for arrays, for functions, for dates, for errors, or for your own constructors. There is one shape: instance, constructor's prototype, Object.prototype, null.
A note on what to actually write:
// __proto__ is legacy. It works everywhere and is not going away,
// but the standard accessors are what belongs in your code:
console.log(Object.getPrototypeOf(nums) === Array.prototype); // true
// Setting a chain after the fact is slow enough that engines warn against
// it. Prefer establishing it at creation, which is the next lesson:
const child = Object.create(Array.prototype);
You can now answer the whiteboard version of this question without memorising a picture. Given any value, its chain is: the object itself, then whatever its constructor's .prototype holds, then Object.prototype, then null. Say that sentence and then it in a console, and the diagram draws itself.
proto is the link an object follows when a lookup fails. .prototype is a property that only functions have, holding the object that instances created by that function will link to. One is on instances, one is on constructors.