bind() y bindAsEventListener() en Prototype, como utilizarlos

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.

  1. 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:
    1.  
    2. var Clase1 = Class.create({
    3.   initialize: function(msg){
    4.     this.mensaje = msg;
    5.   },
    6.   log: function(){
    7.     console.log(this.mensaje);
    8.   }
    9. });
    10. var objeto1 = new Clase1("Mensaje, Objeto1");
    11. var objeto2 = new Clase1("Mensaje, Objeto2");
    12.  
    13. objeto1.log(); //Genera -> Mensaje, Objeto1
    14. objeto2.log(); //Genera -> Mensaje, Objeto2
    15. //Creamos el bind de alerta para que se ejecute en el
    16. //contexto del objeto2.
    17. var log_bind = objeto1.log.bind(objeto2);
    18. 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.

    1. var Clase2 = Class.create({
    2.   initialize: function(msg){
    3.     this.mensaje = msg;
    4.   },
    5.   log: function(){
    6.     console.log(this.mensaje + ‘ ‘ + $A(arguments).join(‘, ‘));
    7.   }
    8. });
    9.  
    10. var objeto3 = new Clase2("Mensaje, Objeto3");
    11. objeto3.log();
    12. var log_bind_mas_argumentos = objeto3.log.bind(objeto3,1,2,3,4,‘ lo que sea’);
    13. 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.

  2. 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:
    1. var obj = {
    2.   name: ‘Un bonito ejemplo’
    3. };
    4.  
    5. function handler(evento){
    6.   var tag = Event.element(evento).tagName.toLowerCase();
    7.   var data = $A(arguments);
    8.   data.shift();
    9.   console.log(this.name + \nHas clickado en ‘ + tag + \nOtros argumentos: ‘ + data.join(‘, ‘));
    10. }
    11. $(‘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:

    1. $(‘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

No hay posts relacionados.

Tags: ,

9 comentarios en “bind() y bindAsEventListener() en Prototype, como utilizarlos”

  1. Bitacoras.com Ha dicho:

    Información Bitacoras.com…

    Si lo deseas, puedes hacer click para valorar este post en Bitacoras.com. Gracias….

  2. xaelvil Ha dicho:

    Algo que guardar y consultar en un futuro, gracias máquina…

  3. naitsir Ha dicho:

    esta buenísimo el artículo, me parece que casi lo entiendo, pero aún tengo un par de dudas, será q puedes aclarármelas??la primera y más importante, a q te refieres con cambiar el contexto del objeto/función, q significa esto??
    hasta donde vi, parece algo así como hacer herencia.
    por otro lado, hara hacer esto, si o si es necesario pasarle un objeto/función como primer parámetro??

    para usar el observe y poder pasar parámetros a la función, creo q siempre es necesario usar el bindAsEventListener verdad???

    y por último, q restricciones se tienen para poder usar estas funciones??

    muchas gracias por tu post, es de mucha ayuda.
    salu2

  4. Francisco Ha dicho:

    @naitsir:

    Cambiar el contexto significa hacer que un método de una instancia se ejecute en una instancia distinta, en lugar del objeto original. En javascript el contexto de los métodos es siempre el mismo por lo que es útil poder cambiar el contexto y forzar que sea el que nosotros queramos.

    Con respecto al uso de bindAsEventListener, no es necesario. Puedes usar otras herramientas de prototype, mira la página correspondiente del API http://www.prototypejs.org/api/function . El sentido de bindAsEventListener es asegurarse que el primer argumento al capturar un evento es el objeto que contiene los datos del evento en sí.

    Las limitaciones… bueno, no se me ocurren, lo que no significa que no existan. Depende del uso que se le de y de lo que quieras hacer o necesites.

    Un saludo y muchas gracias a ti por tu comentario :)

  5. sgwd Ha dicho:

    Hola,

    necesito hacerte una consulta:

    utilizo este codigo:

    Event.observe(’imgTest’, ‘click’, function(event) {
    fxAlgo();
    });

    Mi pregunta es:
    como hago para poder conocer que funcion tiene asignado el elemento ‘imgTest’ para el evento click? es decir obtener como resultado fxAlgo();

    Nota:
    anteriormente, utilizaba el evento onclick en la etiqueta:

    y haciendo luego: $(’imgTest’).onclick

    obtenia:

    function onclick(event) {
    fxAlgo();
    }

  6. naitsir Ha dicho:

    siento responder tan tarde, muchas gracias por la explicación, en verdad me iluminaste… es un quebradero de cabeza esta función, o al menos eso pensaba hasta q leí tu artículo. seguí así!

    salu2

  7. Francisco Ha dicho:

    No existe un método para recuperar esa función (al menos no se me ocurre ninguna), entre otras cosas por que puedes tener varias funciones asignadas. Lo mejor que puedes hacer para solucionar tu problema es almacenar anteriormente esa función en un objeto o de alguna otra forma que te resulte conveniente.

    Un saludo.

  8. sgwd Ha dicho:

    Gracias por responder, sabiendo que no se puede recuperar, voy a guardarlo en un array. slds.

  9. Covi Ha dicho:

    oO’ ¿Facebook? :D
    No sé si me he perdido algo pero me imagino que querrías decir Firebug, ¿no?

    Se agradecen artículos en español sobre Prototype, y la cuestión es que algunos nos acostumbramos demasiado a librerías facilonas olvidando la madre del cordero: JavaScript a pelo y DOM (en este caso eventos); de ahí estas dudas me temo.

Deja un comentario