En programación, a menudo queremos tomar algo y extenderlo.
Por ejemplo: tenemos un objeto user con sus propiedades y métodos, y queremos hacer que admin y guest sean variantes ligeramente modificadas del mismo. Nos gustaría reutilizar lo que tenemos en user; no queremos copiar ni reimplementar sus métodos, sino solamente construir un nuevo objeto encima del existente.
La herencia de prototipos es una característica del lenguaje que ayuda en eso.
[[Prototype]]
En JavaScript, los objetos tienen una propiedad oculta especial [[Prototype]] (como se menciona en la especificación); que puede ser null, o hacer referencia a otro objeto llamado “prototipo”:
Cuando leemos una propiedad de object, si JavaScript no la encuentra allí la toma automáticamente del prototipo. En programación esto se llama “herencia prototípica”. Pronto estudiaremos muchos ejemplos de esta herencia y otras características interesantes del lenguaje que se basan en ella.
La propiedad [[Prototype]] es interna y está oculta, pero hay muchas formas de configurarla.
Una de ellas es usar el nombre especial __proto__, así:
let animal = {
eats: true
};
let rabbit = {
jumps: true
};
rabbit.__proto__ = animal; // establece rabbit.[[Prototype]] = animal
Si buscamos una propiedad en rabbit y no se encuentra, JavaScript la toma automáticamente de animal.
Por ejemplo:
let animal = {
eats: true
};
let rabbit = {
jumps: true
};
rabbit.__proto__ = animal; // (*)
// Ahora podemos encontrar ambas propiedades en conejo:
alert( rabbit.eats ); // verdadero (**)
alert( rabbit.jumps ); // verdadero
Aquí, la línea (*) establece que animal es el prototipo de rabbit.
Luego, cuando alert intenta leer la propiedad rabbit.eats (**), no la encuentra en rabbit, por lo que JavaScript sigue la referencia [[Prototype]] y la encuentra en animal (busca de abajo hacia arriba):
Aquí podemos decir que “animal es el prototipo de rabbit” o que “rabbit hereda prototípicamente de animal”.
Entonces, si animal tiene muchas propiedades y métodos útiles, estos estarán automáticamente disponibles en rabbit. Dichas propiedades se denominan “heredadas”.
Si tenemos un método en animal, se puede llamar en rabbit:
let animal = {
eats: true,
walk() {
alert("Animal da un paseo");
}
};
let rabbit = {
jumps: true,
__proto__: animal
};
// walk es tomado del prototipo
rabbit.walk(); // Animal da un paseo
El método se toma automáticamente del prototipo, así:
La cadena prototipo puede ser más larga: