Javascript: attaching OOP methods to events and the 'this' keyword

荒凉一梦 提交于 2019-12-12 11:44:17

问题


I am new to OOP Javascript and am having trouble with the this keyword and events.

What I'm trying to achieve is: I have multiple DOM objects and want to not only bind a common event to them, but keep some data about the aforementioned objects in a global container (to increase runtime performance).

So what I do is basically this:

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);
}

Later, in the document body, I could just add this:

var Ctds = new ClassThatDoesSomething();

And further on, add DOM elements by:

Ctds.addNodes(ids);

No further implementation code would be required.

QUESTION: How to access the JS class instance in the init and scroll methods and not the window element.

It doesn't have to be through the this keyword, I know, but still I didn't come up with anything.

P.S.

  • addEvent is an extremely basic function to attach events, it's just IE/Fx friendly and does nothing else.
  • The code I'm writing is already functional, but in procedural form, I just wanted to OOP'd it.
  • As a minor sub-question, I got the impression somehow, that getter/setter methods are discouraged in javascript, is it okay if I use them?

回答1:


One thing I notice is that neither init nor scroll is a method on the instance.

So you only need to add init and not this.init to the load event:

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

And similarly:

addEvent(window,'scroll',scroll);

If you do decide to move them to the class (eg this.scroll and this.init etc), you can save a reference to this and refer to it in an anonymous function passed to addEvent:

var self = this;

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

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

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

This is called a closure.




回答2:


function MyConstructor() {
    this.foo = "bar";
    var me = this;
    function myClosure() {
        doSomethingWith(me.foo);
    }
}



回答3:


this is not determined until execution of the function. When attaching an event listener, you are passing a function, which does not carry scope with it. Therefore, on the specified event, the function is running in the scope of window, meaning that this will be equal to window. To force execution in a particular scope, you can use tricks like creating a new variable to equal this, such as:

var that = this;
...
addEvent(window,'scroll', function() {
    that.scroll()
});



回答4:


Add a method to the Function prototype that allows you to bind any function to any object:

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

Declare your event handlers in the instance (keeps things tidy):

function ClassThatDoesSomething() {

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

Now whenever you reference your events, they'll be automatically bound to the class instance. e.g.:

function init() {
  addEvent(window,'scroll',ClassThatDoesSomething.events.scroll);
}



回答5:


You can use closures for that:

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

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



回答6:


Do this:

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);
}



回答7:


This trick should work:

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

Then inside those problematic methods you can use 'This'.

Hope this helps.



来源:https://stackoverflow.com/questions/1578034/javascript-attaching-oop-methods-to-events-and-the-this-keyword

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!