Every JavaScript object has a hidden link to another object, called its prototype. When you ask an object for a property it does not have, JavaScript does not give up. It looks in the prototype.
Think of a student asking a teacher a question. If the student does not know, they ask their teacher. If the teacher does not know, the teacher asks their teacher. That is how property lookup works.
const animal = {
eats: true,
speak() {
return "some sound";
}
};
const dog = Object.create(animal); // a new object whose prototype is `animal`
dog.name = "Rex";
console.log(dog.name); // → Rex (found on dog itself)
console.log(dog.eats); // → true (not on dog: found on its prototype)
console.log(dog.speak()); // → some sound
console.log(dog.hasOwnProperty("eats")); // → false (it is inherited)
dog has only one property of its own (name). eats and speak come from animal, its prototype.
Overriding
A property on the object itself hides one with the same name in the prototype.
const animal = { speak() { return "some sound"; } };
const dog = Object.create(animal);
dog.speak = function () { return "woof"; };
console.log(dog.speak()); // → woof
console.log(animal.speak()); // → some sound (the prototype is unchanged)
Writing never changes the prototype
Assigning a property creates it on the object itself.
const base = { count: 1 };
const child = Object.create(base);
child.count = 2;
console.log(child.count); // → 2
console.log(base.count); // → 1
Why prototypes?
Instead of copying methods onto every object, objects can share them through their prototype. 1,000 dogs can use one speak function. That saves memory, and it is the foundation of inheritance in JavaScript.
You already use prototypes
Arrays get map, filter and push from Array.prototype. Strings get toUpperCase from String.prototype. Every object gets toString and hasOwnProperty from Object.prototype.
const list = [1, 2, 3];
console.log(Object.hasOwn(list, "map")); // → false (not an own property)
console.log(typeof list.map); // → function (inherited from Array.prototype)
console.log(list.map === Array.prototype.map); // → true
Terminology
prototype(the idea): the object that another object delegates to.Object.getPrototypeOf(obj): the standard way to read an object’s prototype.Fn.prototype: a property of constructor functions, used when you create instances withnew Fn(). See Constructor Functions.__proto__: an old, non-standard accessor for the prototype. You may see it in older code. Avoid it in new code.