viernes, 31 de octubre de 2014

Javascript avanzado: objetos, clases y prototipos. Introducción

Javascript es un lenguaje muy completo y muy complejo de aprender, sobre todo la parte referente a objetos, clases, herencia, prototipos, etc. Y esto es porque si bien Javascript no soporta de forma nativa esos conceptos de la orientación a objetos que tan claros están en otros lenguajes como Java, C++ o PHP, todos ellos pueden simularse con las funciones nativas del lenguaje.

Por ello voy a iniciar una serie de artículos sobre Javascript Avanzado.


Creación de un objeto simple

var stack = {
    elements: [],
    push: function(elem) {
        this.elements.push(elem);
    },
    pop: function() {
        var elem = this.elements.pop();
        return elem;
    }
};

En Javascript se puede usar la notación JSON para crear objetos sin tener que crear antes una clase. En el ejemplo creamos un objeto llamado stack que tiene un array de elementos y dos métodos: push() y pop(). La variable resultante es directamente un objeto. La mayoría de los lenguajes orientados a objeto no permiten crear objetos sin haber creado antes una clase, pero Javascript sí.

NOTA: Es innecesario crear un objeto stack en Javascript pues la clase Array ya tiene las funciones push() y pop() de forma nativa, pero me sirve para ilustrar el ejemplo.

stack.push(1);
stack.push('string');
stack.push({ id: 1, name: 'test' });
console.log(stack.pop());

Como se ve podemos usar directamente los métodos del objeto stack, pero en cambio no podemos crear nuevos objetos stack, ya que stack es un objeto y no una clase. Por lo tanto el siguiente código dará error:

var s = new stack;

Además en este tipo de objetos simples todos los métodos y miembros son públicos, lo cual quiere decir que podríamos acceder directamente a la lista de elementos elements, lo cual no suele ser correcto desde el punto de vista de la programación orientación a objeto.


Añadiendo miembros y métodos a un objeto simple

Javascript, a diferencia de otros lenguajes de programación orientados a objetos más tradicionales permite añadir nuevos miembros y métodos a un objeto simple tras su creación. Por ejemplo:

stack.top = function() {
    if(this.elements.length < 1) {
        return null;
    }
    else {
        return this.elements[this.elements.length - 1];
    }
};

Así añadimos el método top() al objeto stack que funcionará exactamente igual que si lo hubiéramos puesto desde el principio.


Creación de una clase

En Javascript no podemos crear una clase como tal, pero sí que podemos simularlo mediante una función. Sí, sí... has leído bien: una función. Esa función además funciona como constructor de la clase. Veamoslo con el mismo ejemplo:

var Stack = function() {
    var elements = [];
    this.push = function(elem) {
        elements.push(elem);
    },
    this.pop = function() {
        var elem = elements.pop();
        return elem;
    }
};

En el constructor de la clase Stack inicializamos un array de elementos y definimos las funciones push() y pop(). Ahora Stack es una clase, no un objeto y por lo tanto no podemos hacer lo siguiente:

Stack.push('elem1');
console.log(Stack.pop());

La forma correcta de hacerlo sería creando primero un objeto de clase Stack.

var st = new Stack;
st.push('elem1');
console.log(st.pop());

Además se da el caso de que ahora el miembro elements es privado lo cual significa que no puede ser accedido desde fuera de la clase.


Añadiendo miembros y métodos a una clase Javascript

Anteriormente vimos como añadir métodos a un objeto Javascript. Aquí también podemos añadir miembros y métodos directamente al objeto st, pero como la variable elements no es un miembro de la clase no podremos acceder a ella. Tendríamos que hacer que la variable elements fuera un miembro de la clase

var Stack = function() {
    this.elements = [];
    this.push = function(elem) {
        this.elements.push(elem);
    },
    this.pop = function() {
        return this.elements.pop();
    }
};

var st1 = new Stack;

st1.top = function() {
    if(this.elements.length < 1) {
        return null;
    }
    else {
        return this.elements[this.elements.length - 1];
    }
};

st1.push('e1');
console.log(st1.top());

Hemos añadido el método top() al objeto st que funcionará como si se hubiera añadido en la definición de la clase (función constructora). Sin embargo ese método es exclusivo del objeto st y no estará disponible para otros objetos Stack. ¿Y podemos añadir un método a una clase? Sí; a través del prototipo:

Stack.prototype.top = function(){
    if(this.elements.length < 1) {
        return null;
    }
    else {
        return this.elements[this.elements.length - 1];
    }
};

Ahora tanto st1 como cualquier otro objeto de clase Stack creado con posterioridad tendrán top() entre sus métodos.


Herencia de clases en Javascript

El concepto de la herencia en Javascript también es extraño si estas acostumbrado a otros lenguajes orientados a objeto. Al no existir clases como tales tampoco hay palabras clave como extends o implements. La herencia se hace asignando el prototipo de una función (clase) a otra. Pero la explicación detallada la vamos a dejar para otro artículo.


Referencias

No hay comentarios:

Publicar un comentario