Ultimos Twitts
Últimas Fotos
Último Post
OOP en Javascript

Javascript debe ser el lenguaje mas malentendido del mundo, pero resulta ser uno de los lenguajes mas interesantes y poderosos que hay, con sus bases funcionales se pueden hacer cosas muy interesantes y una de ellas es la programación orientada a objetos, aun que, sorprendentemente, esto es algo que no muchos saben que se puede hacer y mi intención es darle un par de vueltas en este post.
La gente que ha jugado con javascript estará acostumbrada a código eminentemente procedural con código como el siguiente:
function function_name(param1, param2, param3) {
// Do something!
}
function_name(some, actual, params);
Está bien, se hace lo que se pide pero, imaginen unas 20, 30 o mas funciones de esas y ya tienes una pesadilla.
Luego uno conoce JSON que es excelente para pasar parámetros o transferirlo por la red.
some_function({
arg1: 'value1',
arg2: 'value2'
});
Esto definitivamente hace mas facil entender que se está haciendo, pero todavía falta algo, esas funciones desperdigadas por el mundo me molestan, así que definamos “objetos de verdad” ahora!
function Person(name) {
this.name = name;
}
Person.prototype.greet = function() {
alert('Hello, ' + this.name);
}
// Y lo usamos:
var p = new Person('Sebastián');
p.greet();
Aquí creo que debería aclarar que es Person.prototype, el modelo de objetos de JavaScript se basa en en prototipos y el objeto Person.prototype no es mas que una colección de propiedades que se ván a copiar en toda instancia de Person que se cree, de hecho, nos podemos aprovechar de esto para implementar herencia!
function Employee(name, company) {
this.name = name;
this.company = company;
}
Employee.prototype = new Person();
var e = new Employee('Sebastián', 'Gaaper');
e.greet();
Esto sorprendentemente comienza a verse mejor y se vuelve mucho mas interesante cuando se entienden correctamente las clausuras (que para los que vienen de Ruby notarán que se parecen mucho a los bloques pero un poco mas potentes) ya que usándolas inteligentemente se pueden implementar encapsulamiento y espacios de nombres.
Veamos una clausura básica:
(function() {
var private = 0;
window.increaseValue = function() {
private++;
}
window.getValue = function() {
return private;
}
})();
getValue(); // retorna 0;
increaseValue();
private--; // error: ReferenceError: Can't find variable: private
getValue(); // retorna 1;
Esto básicamente encapsula el valor de private que es inaccesible desde fuera de la clausura y define las funciones increaseValue y getValue que permiten acceder y modificar private. Y para esto solo hizo falta definir una función anonima y ejecutarla!
Pero nos falta una cosa todavía, estas funciones están definidas en window por lo que se corre el riesgo de que existan conflictos de nombre con otro script y para eso acuden los espacios de nombres al rescate!
Namespace = {};
(function($) {
var private = 0;
$.increaseValue = function() {
private++;
}
$.getValue = function() {
return private;
}
})(Namespace);
Namespace.increaseValue();
Namespace.getValue();
Fácil y rápido, hemos cambiado el ejemplo anterior para que utilizara un Espacio de Nombre y no definiera los métodos en window.
La verdad es que JavaScript es un lenguaje muy dinamico y existen otras formas de hacer todo lo que puse aquí cada una con sus pros y contras, pero intenté mantener todo lo mas sencillo posible y utilizando los diseños que a mi me parecen mas elegantes y si tienen alguna idea de como esto se podría hacer mejor, me encantaría que la plantearan en los comentarios.
Para finalizar les dejo un ejemplo que aplica gran parte de lo que puse aquí, es un poco mas complejo pero adelante ;)
(function($) {
// Aquí defino la "clase Foo"
function Foo(text) {
/* Variable de instancia pública */
this.text = text || privateMethod();
/* Variable de instancia privada */
var priv = 'ehem';
/* método público que utiliza la variable privada */
this.setPrivate = function(p) { priv = p; }
/* método privado */
function privateMethod() { return 'this is private: '+priv; }
}
Foo.prototype.getText = function() { return this.text; }
/* Variable de clase privada */
var class_priv = 0;
/* Método de clase público */
Foo.bar = function() {
class_priv++;
return new Foo('bar'+class_priv);
}
/* Método de clase privado */
function helloFoo() { return new Foo('Hello'); }
$.Foo = Foo;
})(window);
var f = new Foo('Hello!');
Y si quedaron con gusto a poco, aquí les dejo un lugar donde encontrar mas información pero en inglés.





