最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

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

programmeradmin2浏览0评论

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 mon 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 e 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?

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 mon 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 e 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?
Share Improve this question asked Oct 16, 2009 at 13:26 raverenraveren 18.5k12 gold badges73 silver badges88 bronze badges
Add a ment  | 

7 Answers 7

Reset to default 10

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.

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

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

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

You can use closures for that:

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

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

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

This trick should work:

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

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

Hope this helps.

发布评论

评论列表(0)

  1. 暂无评论