Prototipos en JavaScript

Prototipos en JavaScript

Cuando hablamos de Javascript, inherentemente tenemos que pensar en objetos y mas aún, en prototipos, esta es su base y su fortaleza (así algunos digan que es su debilidad).

Javascript es un lenguaje basado en prototipos, es decir, usa prototipos para definir sus propiedades, metodos y también, para implementar herencia(prototype inheritance). Los prototipos siguen un patrón por asi decirlo y es algo llamado la cadena de prototipos (prototype chain), la cual voy a definir a continuación.

Cadena de prototipos

En Javascript encontramos dos tipos de datos, las primitivas (string, number, boolean, etc.) y los objetos (arrays, object literals, functions), ambos estan bajo el marco de definición de un objeto, es decir, todos los anteriores son objetos, objetos definidos bajo su marco ya dicho (string, array, etc). Todos esos objetos tienen algo en común y es una propiedad llamada prototipo (prototype), esta propiedad es un objeto que contiene todas las propiedades reusables, metodos y los prototipos del objeto padre. Ok, esa última parte es un poco confusa, ¿una propiedad que es un objeto y que tiene las propiedades de su padre?. Para entenderlo, debemos entender como funciona esta cadena de prototipos, y es heredando las propiedades del objeto padre, recordemos que en Javascript todo objeto tiene un objeto padre, hasta llegar a null, el orden sería como una especie de descendencia jerarquica.

9ywxwqyi3ig0opl5b51g.png

Ahora, llevemoslo a un ejemplo real para poder entender de que hablamos. Definamos un objeto.

const myCar = {
    make: 'Ford',
    model: 'Mustang',
    year: 1969
};

Este objeto tiene dos propiedades, name y lastname, para poder saber nuestro wrapper object o en otras palabras, a que tipo de dato pertenece (por definición es un objeto, pero vamos a verificarlo) usamos la función getPrototypeOf.

const wrapperProto = Object.getPrototypeOf(myCar);
console.log(wrapperProto) // Object

La respuesta de la consola nos muestra el tipo de elemento, que como dije antes es un objeto (constructor: Object)

Si ahora obtenemos el tipo del elemento wrapperProto vamos a obtener Object de nuevo, este sería el tipo definido por nosotros.

const wrapperType = Object.getPrototypeOf(wrapperProto);
console.log(wrapperType) // Object

Si repetimos el mismo paso, vamos a llegar a la raiz del arbol de jerarquía, que como dije antes sería null.

const parentType = Object.getPrototypeOf(wrapperType );
console.log(parentType) // null

Para que esté completa la definición de la cadena de prototipos, tenemos también que referenciar algo llamado la busqueda de metodos o method lookup, esta funcionalidad de Javascript establece que si intentamos acceder a una propiedad o método de nuestro objeto, y no es encontrada, Javascript continuará buscando en la jerarquía ascendente (parent object) hasta llegar a encontrarla o llegar a null.

Herencia de Prototipos

Ya conocemos como funciona la cadena de prototipos y la busqueda de métodos, basicamente ya podemos definir un patrón de herencia con esta funcionalidad, pero veamos esto con un ejemplo simple.

const sayayin = {
  isPure: true,
  kamehameha() {
   console.log('kamehamehaaaaa');
  }
}

const goku = {
  name: 'kakaroto',
  age: 30
}

Object.setPrototypeOf(goku, sayayin);
console.log(goku.isPure) // true;
goku.kamehameha() // kamehamehaaaaa
console.log(Object.getPrototypeOf(goku) === sayayin); // true

Creamos un objeto padre llamado sayayin y un objeto hijo llamado goku, luego le asignamos el prototipo del objeto padre (setPrototypeOf), con eso heredamos las propiedades y ya podemos llamarlas junto con sus métodos. (los invito a copiar y pegar ese código en la consola del navegador). Entonces, el prototipo de goku es sayayin, el prototipo de sayayin es Object y el prototipo de Object es null. (pueden hacer el mismo ejercicio que se hizo antes).

Herencia en ES6

ES6 introdujo el manejo de clases en javascript, pero basicamente es la misma herencia de prototipos con una sintaxis mas acomodada a la definición de programación orientada a objetos tradicional de lenguajes como Java, C#, C++.

Object.Create

En javascript actualmente podemos definir objetos de diferentes maneras, pero con Object.create tenemos la opción de crear nuestros objetos sin necesidad de definir una función constructora.

Por ejemplo, creando un objeto por medio de una función, asignamos variables de entrada al constructor al crear objetos de ese tipo.

function Auto(make, model, year, owner) {
  this.make = make;
  this.model = model;
  this.year = year;
  this.owner = owner;
}

let eagle = new Auto('Eagle', 'Talon TSi', 1993, rand);
let nissan = new Auto('Nissan', '300ZX', 1992, ken);

Con Object.create sería algo como:

var Animal = {
  type: 'Mamifero', // Valor predeterminado
  displayType: function() { 
    console.log(this.type);
  }
};

// Crea un nuevo tipo de animal llamado animal1
var raton = Object.create(Animal);
raton.displayType(); // Muestra: Mamifero

// Crea un nuevo tipo de animal llamado Fishes
var tiburon = Object.create(Animal);
tiburon.type = 'Pez';
tiburon.displayType();    // Muestra: Pez