Prototype y herencia prototipal en JavaScript
Tags: javascript, webdev, beginners, spanish
Published: 2020-11-08 04:44:24

El prototype o prototipo es un concepto casi único de JavaScript. Este concepto se aleja de la forma en la cual normalmente se manejan las clases en un lenguaje de programación. En JAVA, por ejemplo, creamos una clase y luego la instanciamos. Pero en JS eso no se puede hacer, porque el pequeño gran detalle es que: **en JavaScript no existen las clases**.

Al todo ser objetos en este lenguaje de programación debemos instanciarlos a partir de un objeto original, o bien, heredar a otros objetos. Y es aquí donde aparecen los conceptos de prototipo y su modelo de herencia prototipal.

## ¿Que es un prototipo y la herencia prototipal?

> 💡 Un prototipo es un objeto que existe como una propiedad en todas las funciones de JavaScript.

¿No recuerdas que es una propiedad? Tranqui, a todos nos pasa. Como ya lo mencioné antes, JavaScript está basado en objetos. Entonces, **un objeto es una colección de propiedades, y una propiedad es una llave (key) y un valor para esa llave (value)**. Aquí un ejemplo:

![Prototype y herencia prototipal](https://dev-to-uploads.s3.amazonaws.com/i/bz0810b6jioxav7sdz8f.png)

Siempre que pedimos una propiedad o un método a una función y no se encuentra, se busca en el prototipo del objeto. El prototipo, a su vez es también un objeto llamado `_Prototype_` y este objeto `_Prototype_` es una propiedad del objeto global: `_Object_`. Y como a todo objeto en JavaScript, se le pueden agregar nuevas propiedades y métodos. 

_// En este lenguaje pasan cosas raras... Lo sé. Sigamos:_

Esto se le conoce como **cadena de prototipos**. Y es la razón por la cual otros objetos pueden tener disponibles propiedades y métodos de otros objetos. Veamos unos ejemplos:

Primero, creamos un objeto normal:

```
      const character = {
        name: "Vegeta",
      };

      character.hi = function () {
        alert(`Me llamo ${this.name} y soy un personaje`);
      };

      character.hi();
```

Esto con un objeto puede estar bien y no causar problemas. Pero, ¿y si tenemos más de 50 objetos? ¿vamos a crear un función saludar por cada objeto? Esto es muy poco escalable. Busquemos otra forma:

```
      const characterMethods = {
        hi: function () {
          console.log(`Me llamo ${this.name} y soy un personaje`);
        },
      };

      function Character(name) {
        const character = {
          name: name,
        };

        character.saludar = characterMethods.hi;
        return character;
      }

      const vegeta = Character("Vegeta");
      vegeta.hi();

      const pikachu = Character("Pikachu");
      pikachu.hi();
```

Más sencillo y más funcional ¿cierto? Simplemente creamos dos objetos, uno donde guardamos los métodos y propiedades (_characterMethods_) y otro donde guardamos nuestros personajes (Characters). Pero... esto se puede hacer de forma mucho más sencilla con los prototipos y la herencia prototipal.

Y aquí veremos algo nuevo llamado: `object.create`. Básicamente, es uno de los métodos para crear objetos en JavaScript. Recibe dos argumentos: `Object.create(prototypeObject, propertiesObject)`. El prototipo del objeto y las propiedades del objeto. Veamos su funcionamiento:

```
      function Character(name) {
        // Iniciamos el uso del Object.create.
        const character = Object.create(Character.prototype);
        character.name = name;

        return character;
      }

      // Iniciamos el uso de Object.prototype
      Character.prototype;
```

Como lo mencioné al principio de este post en la definición de prototipo, todas las funciones tienen un objeto prototype. Al principio `Character.prototype` (el objeto de las funciones) es un objeto vacío. Pero, una vez más, como lo dije al principio: a todo objeto se le pueden agregar nuevas propiedades y métodos. Hagamos que `prototype` deje de estar vacío 👇

```
      function Character(name) {
        // Iniciamos el uso del Object.create.

        const character = Object.create(Character.prototype);
        character.name = name;

        return character;
      }

      // Iniciamos el uso de Object.prototype
      Character.prototype;

      // Agregamos un método a Character.prototype
      Character.prototype.hi = function () {
        console.log(`Me llamo ${this.name} y soy un personaje`);
      };

      const vegeta = Character("Vegeta");
      // Usamos el método agregado a Character.prototype
      vegeta.hi();

      const pikachu = Character("Pikachu");
      pikachu.hi();
```

¡Y listo! ¡Funciona! El código en el que trabajamos ahora es mucho más limpio, hay menos código repetido y sobre todo y más importante, es mucho más reutilizable y mantenible. Podemos agregar nuevos métodos y propiedades sin que todo se rompa, simplemente tendríamos que agregar un nuevo método a `Character.prototype`. No tendremos que crear muchas funciones o hacer que muchas propiedades y métodos dependan de un solo objeto.

### ¿Qué aprendizaje te puedes llevar de este post?
- Todo en JavaScript acaba en el objeto `Object`, el cual es el objeto global. Todo se hereda de allí y si alguna función no encuentra un método o una propiedad la buscará en el objeto global. Si no la encuentra en el objeto global se imprimirá un error.
- La forma en la que un objeto puede acceder a propiedades y métodos de otro objeto hasta llegar al objeto global se llama **herencia prototipal**.
- `propotype` es un objeto que tienen todas las funciones en JavaScript. Inicia vacío pero se le pueden ir agregando nuevos métodos y propiedades.

Espero que hayas podido comprender un poco más este tema.

Nos vemos en un próximo post. 🚀

### Fuentes consultadas:
[MDN Web Docs](https://developer.mozilla.org/es/docs/Learn/JavaScript/Objects/Object_prototypes)
[Platzi](https://www.platzi.com)