Prototipos

JavaScript es un lenguaje orientado a objetos (en JavaScript I vimos los objetos literales). Sin embargo, a diferencia de otros lenguajes orientados a objetos como Java, Ruby, C#, etc. que utilizan clases, JavaScript está basado en prototipos.

Nota: ES6 introduce clases a JavaScript. Sin embargo, las nuevas clases de JavaScript no son más que un truco sobre los prototipos. En el capítulo de ES6 hablaremos sobre las clases.

En JavaScript, cada objeto está asociado a otro objeto (el prototipo) del cual hereda sus propiedades.

Cuando creas un objeto literal (p.e. { nombre: "Pedro" }) el prototipo es Object.prototype, que es el prototipo raíz de todos los objetos.

Función constructora

Existe otra forma de crear objetos en JavaScript y es con una función constructora. Veamos un primer ejemplo de una función constructora:

var Persona = function(name) {
this.name = name;
}

Fíjate que para definir las propiedades utilizamos la palabra clave this. Aunque parece una función normal (y en cierta forma lo es), con esta función podemos crear varios objetos utilizando la palabra clave new.

var p1 = new Persona("Pedro");
var p2 = new Persona("Juan");

Nota: No olvides el new cuando utilices una función constructura. Por convención las funciones constructoras se nombran en mayúsculas para diferenciarlas de una función normal. Siempre que veas una función en mayúscula ya sabes que es una función constructura y que debes utilizar new para invocarla.

Accediendo a las propiedades de un objeto

En JavaScript I vimos que es posible acceder a las propiedades de un objeto utilizando la notación de corchetes ([]) o punto (.):

obj["propiedad"];
obj.propiedad;

Ahora que sabes que todo objeto tiene un prototipo del que hereda sus propiedades, veamos cómo busca JavaScript las propiedades en la jerarquía de prototipos:

  1. Primero busca sobre el objeto directamente. Si la encuentra la devuelve.

  2. Si no la encuentra, busca en el prototipo del objeto. Si la encuentra la devuelve.

  3. Si no la encuentra, busca en el prototipo del prototipo, y así sucesivamente hasta que llega al prototipo raíz Object.prototype.

  4. Si no la encuentra en ningún objeto de la jerarquía retorna undefined.

Agregando propiedades al prototipo de un objeto

Para agregar una propiedad a todos los objetos que han sido creados a partir de una misma función constructora, puedes agregar las propiedades al prototipo. Por ejemplo:

var Persona = function(nombre, apellido) {
this.nombre = nombre;
this.apellido = apellido;
};
Persona.prototype.saluda = function() {
return "Hola " + this.nombre;
};

Ahora todos los objetos creados a partir de la función constructora Persona van a tener la propiedad saluda (no importa si fueron creados antes de definirla):

var pedro = new Persona("Pedro", "Perez");
console.log(pedro.saluda()); // imprime "Hola Pedro"

Lo interesante es que, de esta forma, puedes agregarles métodos a los objetos nativos de JavaScript como Array y Date, entre muchos otros.

Por ejemplo, imagina que queremos agregar un método a los arreglos que sume todos los elementos, podemos agregarle el método sum a Array.prototype:

Array.prototype.sum = function() {
var total = 0;
for (var i=0; i < this.length; i++) {
total += this[i];
}
return total;
}

Ahora podemos usar este método sobre cualquier arreglo:

[1, 2, 3].sum(); // retorna 6