Herencia en JavaScript (Prototypal Inheritance).

Jorge Rodriguez
Continuum
Published in
3 min readAug 6, 2008

--

Seguimos con JavaScript. En esta ocasión traduciremos el articulo de Douglas Crockford (Arquitecto JavaScript de Yahoo!) sobre Prototypal Inheritance (La forma nativa en que el lenguaje permite implementar herencia).

— -

Hace cinco años, escribí “Classical Inheritance in JavaScript”. Mostraba como JavaScript es un lenguaje que no contiene clases (class-free), y que tiene suficente poder expresivo para simular sistemas clásicos de herencia. Mi estilo de programación ha evolucionado desde entonces, como debería evolucionar el de cualquier buen programador. He aprendido a aceptar y usar el prototipalismo, y me liberado de los confines del modelo clásico.

Mi labor fue desconsertante, porque JavaScript en sí entra en conflicto con su naturaleza de prototipo. En un sistema basado en prototipos, los objetos heredan de otros objetos. Sin embargo en JavaScript en vez de tener un operador que hace esta operación, lo que se tiene es el operador new, de forma que:

new f()

produce un nuevo objeto que hereda de:

f.prototype

Esto fue hecho intencionalmente para que el lenguaje pareciera familiar a los programadores entrenados en los modelos clásicos, pero falló en conseguirlo al ver la baja opinión que tienen los programadores Java de JavaScript. El patrón constructor de JavaScript oscurece la naturaleza real de prototipo de JavaScript. Como resultado hay pocos programadores que saben como realmente usar el lenguaje de forma efectiva.

Afortunadamente, es fácil crear un operador que implemente herencia de prototipos real. Lo tengo en las librerías estándar de mi toolkit, y lo recomiendo altamente a todos.

function object(o) {
function F() {}
F.prototype = o;
return new F();
}

La función object() recibe un objeto antiguo como parámetro y retorna un objeto nuevo que hereda del antiguo. Si intentamos obtener un miembro del objeto nuevo y no está, entonces el objeto antiguo va a proveer el miembro. Objetos heredan de objetos. Que puede ser mas orientado a objetos que eso?

Entonces, en vez de crear clases, hacemos objetos prototipos, y entoces usamos la function object() para crear nuevas instancias. En JavaScript los objetos son mutables, asi que podemos aumentar las nuevas instancias. agregandole nuevos atributos y métodos. Estos entonces pueden actuar como prototipos para nuevos objetos. No es necesario tener clases para hacer muchos objetos similares.

Por conveniencia, podemos crear funciones que llamen a la función object() por nosotros, y proveer de esta forma nuevas funcionalidades tales como aumentar nuevos objetos con métodos privilegiados (Nota del traductor : Métodos privilegiados son métodos que pueden acceder a variables y métodos privados del objeto y que son accesibles desde métodos publicos o desde el exterior). Normalmente los llamo funciones “makers”. Si tenemos una función maker que llama otra función maker en vez de llamar a la función object(), entonces lo que tenemos es herencia parasitaria.

He encontrado que usando estas herramientas, junto con las lambdas de JavaScript (Nota del traductor: lambda se refiere a la programación funcional, equivalente a lambda de python, ver Closures en JavaScript) y objetos literales, puedo escribir programas bien estructurados que son grandes, complejos y eficientes. El modelo clásico de herencia es hoy por mucho el más popular, pero creo que el modelo de objetos de ptototipos es más capaz y ofrece más poder expresivo.

Aprender esos patrones además me hizo un mejor programador del estilo clásico. Elementos del mundo dinámico pueden tener aplicación en el mundo estático.

2006–06–07

Aquí hay otra formulación:

Object.prototype.begetObject = function () {
function F() {}
F.prototype = this;
return new F();
};
newObject = oldObject.begetObject();
...
2007-04-02El problema con la función object() es que esta es global, y las variables globales son problemáticas. El problema con Object.prototype.begetObject es que puede producir resultados inesperados cuando begetObject es sobre-escrito.Entonces Yo prefiero la siguiente formulación:if (typeof Object.create !== 'function') {
Object.create = function (o) {
function F() {}
F.prototype = o;
return new F();
};
}
newObject = Object.create(oldObject);
...2008-04-07---ConclusiónLa mayoría de los programadores (me incluyo) está acostumbrado al modelo clásico de herencia entre objetos, o lo que es más, de herencia entre clases. En este articulo Douglas Crockford nos enseña la transparencia y el poder expresivo del modelo de herencia de prototipos de JavaScript.

--

--