Herencia en JavaScript (Prototypal Inheritance).

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-02

El 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ón

La 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.

2 comentarios en “Herencia en JavaScript (Prototypal Inheritance).

  1. GVG

    Hola, me gusto bastante su blog, muy interezante.
    Ahora estaba viendo un tema parecido, queria alguna forma facil sintaxicamente para escribir clases heredables en javascript, pero en JSON.

    antes escribia los objetos como:
    function a(parameters)
    {
    var object = {att1:”,init:function()}
    object.init();
    return object;
    }
    esto me daba el poder de controlar que se hace cuando se inicializan los objetos, pensando en que el objeto puede reaccionar al contexto, como la hora, o una validacion etc.

    pero esto no sirve mucho cuando se trata de herencia.
    lo mas cercano que he obtenido, es la idea de extender las propiedades de otro objeto en la inicializacion del que hereda.
    ven algo parecido que pueda servirme?.

    Responder
  2. wariodiaz

    Saludos!..
    ps tengo una preguntilla… aver tu que opinas… ps ya tengo ratito manejando “OOP” en JavaScript, ahora me dio por publicar la infinad de “Clases” que he ido haciendo, pues la duda va mas al termino correcto que definiria a una “Clase” en JavaScript, he visto que en algunos lados le llaman “Clase” en algunos otros lados he leido “Pseudoclase” yo un tiempo le llame JSON auque creo que este mas bien refiere a {var1:valor, var2:valor} y ps lleyendo y haciendo analogia creo que el termino mas correcto es llamarles Prototipos, pero no tengo una cita que me confirme que es el termino correcto, no se tu que opinas JSON, Clase, Pseudoclase o Prototipo?

    Responder

Agregar un comentario

Su dirección de correo no se hará público. Los campos requeridos están marcados *