Desde que empecé a trabajar mi función principal es la de desarrollador web. Básicamente me peleo todo el dÃa con Prototype y con AJAX. Después de unas cuantas semana Prototype se ha convertido en parte en un gran aliado, pero también en un enemigo a batir. Conocer el framework con profundidad es esencial para trabajar con él y a veces no es fácil. Una de las cosas que mas trabajo me costó entender fue la utilidad de las funciones bind() y bindAsEventListener(). Ambas son muy potentes y muy útiles cuando se utilizan bien, pero comprender su uso puede ser difÃcil y a veces nos pueden dar quebraderos de cabeza.
Voy a intentar explicar de forma clara y simple como se usan estas dos funciones y para qué sirven. Vayamos por partes.
bind(): Es una de las estrellas en Prototype y también es una de las más trabajo suele costar entender. Imaginemos un objeto que tiene métodos para acceder a sus datos miembro. Usando bind() podemos hacer que esos objetos accedan a datos miembro de otros objetos en lugar de a los del objeto original. Veamos un ejemplo:
-
-
var Clase1 = Class.create({
-
initialize: function(msg){
-
this.mensaje = msg;
-
},
-
log: function(){
-
console.log(this.mensaje);
-
}
-
});
-
var objeto1 = new Clase1("Mensaje, Objeto1");
-
var objeto2 = new Clase1("Mensaje, Objeto2");
-
-
objeto1.log(); //Genera -> Mensaje, Objeto1
-
objeto2.log(); //Genera -> Mensaje, Objeto2
-
//Creamos el bind de alerta para que se ejecute en el
-
//contexto del objeto2.
-
var log_bind = objeto1.log.bind(objeto2);
-
log_bind(); //Genera -> Mensaje, Objeto2
Como vemos, la llamada a log_bind() realiza la llamada a objeto1.bind() usando el contexto del objeto2, lo cual en terminos prácticos equivale a hacer objeto2.bind()
También podemos usar bind() para añadir argumentos a la llamada a una función. Veamos un ejemplo de esto.
-
var Clase2 = Class.create({
-
initialize: function(msg){
-
this.mensaje = msg;
-
},
-
log: function(){
-
console.log(this.mensaje + ‘ ‘ + $A(arguments).join(‘, ‘));
-
}
-
});
-
-
var objeto3 = new Clase2("Mensaje, Objeto3");
-
objeto3.log();
-
var log_bind_mas_argumentos = objeto3.log.bind(objeto3,1,2,3,4,‘ lo que sea’);
-
log_bind_mas_argumentos();
Esta vez no cambiamos el contexto de la función, pero añadimos varios argumentos extra que luego se extraen usando $A(arguments), convirtiéndolos asà en un Array de Prototype.
bindAsEventListener(): Una vez hemos comprendido el uso que tiene bind() es fácil entender la dinámica de bindAsEventListener(). Su funcionamiento es el mismo que el de la función bind() pero con adaptaciones especÃficas para un contexto concreto, el de la captura de eventos.Este es el mismo ejemplo que hay en el API de Prototype pero un poco retocado:
-
var obj = {
-
name: ‘Un bonito ejemplo’
-
};
-
-
function handler(evento){
-
var tag = Event.element(evento).tagName.toLowerCase();
-
var data = $A(arguments);
-
data.shift();
-
console.log(this.name + ‘\nHas clickado en ‘ + tag + ‘\nOtros argumentos: ‘ + data.join(‘, ‘));
-
}
-
$(‘elemento’).observe(‘click’, handler.bindAsEventListener(obj, 1, 2, 3));
Por partes, el objeto obj tiene una propiedad name y la función handler(evento) se encarga de manejar el evento una vez se ha disparado. Esta función extrae el nombre del elemento de la página que ha disparado el evento, los argumentos extra pasados a la función y los muestra todos por la consola de facebook. La clave de todo el ejemplo es la lÃnea:
-
$(‘elemento’).observe(‘click’, handler.bindAsEventListener(obj, 1, 2, 3));
Esta lÃnea asigna la función handler(evento) como manejadora del evento onclick del elemento y además cambia su contexto al del objeto obj y le pasa 3 números como argumento. Pero echando un segundo vistazo a la función vemos que en ningún momento le pasamos el argumento evento. Esa es precisamente la función especial de bindAsEventListener() pasar como primer argumento el objeto de la clase Event que representa al evento que se ha disparado.
Usando bindAsEventListener() siempre recibiremos el objeto Event como primer argumento, sin necesidad de pasar ese evento de forma manual.
Espero que después de este par de ejemplo quede todo un poco más claro, como siempre se aceptan preguntas, dudas y sugerencias
y para todo el código que necesitéis pegar podéis usar Pastie