- 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?