- In JavaScript, objects have a special hidden property [[Prototype]], that is either null or references another object.
- That object is called “a prototype”:
- That
[[Prototype]]
has a “magical” meaning.
- When we want to read a property from
object
, and it’s missing, JavaScript automatically takes it from the prototype.
- In programming, such thing is called “prototypal inheritance”.
- The property
[[Prototype]]
is internal and hidden, but there are many ways to set it.
- Note that
__proto__
is not the same as [[Prototype]]
.
__proto__
is a historical getter/setter for [[Prototype]]
- It exists for historical reasons, in modern language it is replaced with functions
Object.getPrototypeOf/Object.setPrototypeOf
that also get/set the prototype.
let animal = {
eats: true
};
let rabbit = {
jumps: true
};
// Sets animal to be a prototype of rabbit.
rabbit.__proto__ = animal;
// we can find both properties in rabbit now:
console.log(rabbit.eats); // "true" from animal
console.log(rabbit.jumps); // true
- If we have a method in
animal
, it can be called on rabbit
:
let animal = {
eats: true,
walk() {
alert("Animal walk");
}
};
let rabbit = {
jumps: true,
__proto__: animal
};
// walk is taken from the prototype
rabbit.walk(); // Animal walk
- There are actually only two limitations:
- The references can’t go in circles.
- JavaScript will throw an error if we try to assign
__proto__
in a circle.
- The value of
__proto__
can be either an object or null
, other types (like primitives) are ignored.
- Also it may be obvious, but still: there can be only one
[[Prototype]]
.
- An object may not inherit from two others.
- The prototype is only used for reading properties.
- Write/delete operations work directly with the object.
- That’s for data properties only, not for accessors.
- If a property is a getter/setter, then it behaves like a function: getters/setters are looked up in the prototype.
- An interesting question may arise in the example above: what’s the value of
this
inside set fullName(value)
?
- Where the properties
this.name
and this.surname
are written: into user
or admin
?