js magic warning

Bueno, mi primer post aqui será sobre mi querido javascript. Javascript es un lenguaje bastante divertido, con mucha magia, pero como dijo un heroe, “un gran poder significa una gran responsabilidad.”, y he aquí una historia que me sucedió hoy, supongamos que tenemos un inofensivo método, este método puede pasarse como callback, de modo que pasaremos la funcionalidad de un lado a otro. Veamos un ejemplo:

var log = function(a) { console.log(a); };
function myFunc() {
  log('paso 1');
  // ...
  log('paso 2');
  // ...
}

Bien, sí, esto funcionará como esperamos, y la salida sería:

paso 1
paso 2

Perfecto, pero que pasa si en lugar de definir: log = function(a) { console.log(a); }, definieramos: log = console.log ..? Bueno, la realidad es poco fiable, resulta que chrome nos dirá: TypeError: Illegal invocation al momento de invocar log('...');, pero por el contrario, node.js nos acepta el truco y hace justo lo que queremos. Pero esto no es todo, veamos el siguiente ejemplo:

function list() {
  var all = [];
  return {
    push: function(a) {
      all.push(a);
    },
    push1: all.push,
    all: function() {
      return all;
    }
  }
}
l = new list();
l.push(1);
l.push1(2);
l.push(3);
l.push1(4);
console.log(l.all());

Bueno, que creen ? sorpresa !, el resultado es, tanto en chrome como en node.js, el siguiente:

[ 1, 3 ]

El “porque” ?… Resulta que cuando llamamos a l.push1(..);, el método push() se ejecuta sobre <l> lo que significa que intentará insertar el elemento a <l> y no a <l.all>, de hecho, si lo hacemos mediante l.push1.apply(l.all(), [5]);, funcionará a la perfección.

Bueno, espero a alguien le sirva o al menos le haya interesado xD.. Diviértanse.-

Did you like this? Share it:
  • http://www.ubuntutol.blogspot.com GABOLinux

    imagenes men :wink:

  • @guilespi

    En realidad esta mal interpretada la conclusion del ejemplo.

    El problema no lo tenes por un cambio de quien es this.

    Lo que esta pasando es que el retorno de la funcion list() es un hash que tiene dos funciones (push y all) que capturaron el valor de var all cuando fueron definidas (o sea closures).

    Sin embargo push1 es simplemente un puntero a una funcion, no tiene concepto de this, mas alla que hayas obtenido el function pointer a partir del array all.

    Creo que te quedo medio mezclado el efecto del closure con cambiar el this de una funcion, lo que hace al sample poco claro.

    Lo correcto para tu ejemplo si queres modelar un objeto a partir de la funcion list() hubiera sido:

    function list() {
    var self = this;
    self.all = [];
    self.push_back = function(a) {
    //aca podrias usar el self capturado en lugar de this
    this.all.push(a);
    }
    return self;
    }
    var l = new list();
    l.push_back(‘dah’);

    Y una mejor manera aun seria usando prototypes

    function list() {
    this.all = [];
    return this;
    }

    list.prototype.push_back = function(a) {
    this.all.push(a);
    }

    Slds