Soy nuevo en OOP Javascript y tengo problemas con la palabra clave this y los eventos.

Lo que estoy tratando de lograr es: tengo varios objetos DOM y quiero no solo vincular un evento común a ellos, sino mantener algunos datos sobre los objetos mencionados en un contenedor global (para aumentar el rendimiento del tiempo de ejecución).

Entonces, lo que hago es básicamente esto:

function ClassThatDoesSomething() {
    /* keeps node ids for processing in this.init */
    this.nodes = new Array();

    /* keeps processed node data for fast access */
    this.nodeData = new Array();

    this.sthAddNodes = function(/* ids */) {
        /* appends node ids to local variable (this.nodeData) */
    }

    function init() {
        /* gathers data from all nodes that were 
           added before and stores it in this.nodeData */

        /* here, unsurprisingly, 'this' references the window element*/

        addEvent(window,'scroll',this.scroll);
    }

    function scroll() {
        /* do stuff when user scrolls the page */

        /* 'this' references the window element here too */
    }
    addEvent(window,'load',this.init);
}

Más tarde, en el cuerpo del documento, podría agregar esto:

var Ctds = new ClassThatDoesSomething();

Y más adelante, agregue elementos DOM por:

Ctds.addNodes(ids);

No se requerirá más código de implementación.

PREGUNTA : Cómo acceder a la instancia de clase JS en los métodos init y scroll y no el elemento de ventana .

No tiene que ser a través de la palabra clave this, lo sé, pero aún así no se me ocurrió nada.

PD

  • addEvent es una función extremadamente básica para adjuntar eventos, solo es compatible con IE / Fx y no hace nada más.
  • El código que estoy escribiendo ya es funcional, pero en forma de procedimiento, solo quería OOP.
  • Como una subpregunta menor, tuve la impresión de alguna manera, de que los métodos getter / setter están desaconsejados en javascript, ¿está bien si los uso?
4
raveren 16 oct. 2009 a las 17:26

7 respuestas

La mejor respuesta

Una cosa que noto es que ni init ni scroll es un método en la instancia.

Por lo tanto, solo necesita agregar init y no this.init al evento de carga:

addEvent(window,'load',init); // No "this." needed

Y de manera similar:

addEvent(window,'scroll',scroll);

Si decide moverlos a la clase (por ejemplo, this.scroll y this.init, etc.), puede guardar una referencia a this y hacer referencia a ella en una función anónima pasada a {{X3 }}:

var self = this;

this.init = function() {
    addEvent(window, 'scroll', function() {
        self.scroll()
    })
};

this.scroll = function() { /* ... */ };

addEvent(window,'load',function() {
    self.init()
});

Esto se denomina cierre.

10
Roatin Marth 16 oct. 2009 a las 14:37

Este truco debería funcionar:

function ClassThatDoesSomething() {
...
    this.This = this;
...
}

Luego, dentro de esos métodos problemáticos, puede usar 'This'.

Espero que esto ayude.

-1
NawaMan 16 oct. 2009 a las 13:36

Haga esto:

var ClassThatDoesSomething = function() {
    /* keeps node ids for processing in this.init */
    this.nodes = new Array();

    /* keeps processed node data for fast access */
    this.nodeData = new Array();
}

ClassThatDoesSomething.prototype.sthAddNodes = function(/* ids */) {
        /* appends node ids to local variable (this.nodeData) */
    }
}

ClassThatDoesSomething.prototype.init = function() {
        /* gathers data from all nodes that were 
           added before and stores it in this.nodeData */

        /* here, unsurprisingly, 'this' references the window element*/

        addEvent(window,'scroll',this.scroll);
    }
}
ClassThatDoesSomething.prototype.scroll = function() {
        /* do stuff when user scrolls the page */

        /* 'this' references the window element here too */
    }
    addEvent(window,'load',this.init);
}
0
JoshNaro 16 oct. 2009 a las 13:45

Puede usar cierres para eso:

function ClassThatDoesSomething() {
    var self=this;
    // ...

    function init() {
        addEvent(window,'scroll',self.scroll);
    }
}
0
Mikhail Korobov 16 oct. 2009 a las 13:34

Agregue un método al prototipo de función que le permita vincular cualquier función a cualquier objeto:

Function.prototype.bind = function(object) {
   var __method = this;
   return function() {
      return __method.apply(object, arguments);
   };
};

Declare sus controladores de eventos en la instancia (mantiene las cosas ordenadas):

function ClassThatDoesSomething() {

  this.events = {
    init: ClassThatDoesSomething.init.bind(this),
    scroll: ClassThatDoesSomething.scroll.bind(this),
    etc: ClassThatDoesSomething.etc.bind(this)
  };
  ...
}

Ahora, siempre que haga referencia a sus eventos, se vincularán automáticamente a la instancia de clase. p.ej.:

function init() {
  addEvent(window,'scroll',ClassThatDoesSomething.events.scroll);
}
1
Civil Disobedient 16 oct. 2009 a las 13:52

this no se determina hasta la ejecución de la función. Al adjuntar un detector de eventos, está pasando una función , que no tiene alcance. Por lo tanto, en el evento especificado, la función se ejecuta en el ámbito de window, lo que significa que this será igual a window. Para forzar la ejecución en un ámbito particular, puede usar trucos como crear una nueva variable igual a this, como:

var that = this;
...
addEvent(window,'scroll', function() {
    that.scroll()
});
1
geowa4 16 oct. 2009 a las 13:45
function MyConstructor() {
    this.foo = "bar";
    var me = this;
    function myClosure() {
        doSomethingWith(me.foo);
    }
}
2
Jonathan Feinberg 16 oct. 2009 a las 13:36