在类中使用window.addEventListener时,此更改的上下文

时间:2012-11-23 15:40:57

标签: javascript

我正在为我正在开发的游戏编写一个类,它根据页面URL中的哈希更改来控制应用程序路由。

我的问题是,在将主路由功能附加到hashchange事件之后,“this”的上下文会更改为“window”。

以下是目前的代码:

Game.Router = function() {

return {

    init: function() {

        window.addEventListener('hashchange', this.route, false);

    },

    route: function(e) {

        e.preventDefault();
        var routingLocation = e.newURL.substr(e.newURL.indexOf('#!/') + 3, e.newURL.length);

        switch(routingLocation) {
            case "new":
                this.toggleView('Game');
                break;
            case "instructions":
                this.toggleView('Instructions');
                break;
            case "scores":
                this.toggleView('Scores');
                break;
            case "about":
                this.toggleView('About');
                break;
        }

    },

    toggleView: function(viewID) {

        var els = document.querySelectorAll('section');
        for(var i=0, l=els.length; i<l; i++) {
            if(els[i].id == viewID) {
                els[i].className = 'currentGameSection';
            } else {
                els[i].className = '';
            }
        }

    }

}

}();

当我尝试在路由功能的switch语句中调用this.toggleView时,事实证明“this”已经从Game.Router变为window。可以通过用Game.Router.toggleView替换this.toggleView来解决这个问题,但这并不理想。

有人可以帮我理解为什么在添加事件监听器后“this”上下文会发生变化吗?

3 个答案:

答案 0 :(得分:4)

由于您使用的是addEventListener,只需向对象添加handleEvent方法,然后传递对象而不是处理程序。

Game.Router = function() {

    return {
          // vv--- add this
        handleEvent: function(e) {
            if (e.type === "hashchange")
                return this.route();
        },

        init: function() {
                             // pass the object---vv
            window.addEventListener('hashchange', this, false);
        },

        route: function(e) {
            // your route code
        },

        toggleView: function(viewID) {
            // your toggleView code
        }
    }
}();

这样做会导致对象实现 EventListener 接口。因此,对象本身成为有效的事件处理程序,可以传递给addEventListener而不是函数。

因此,当任何偶数发生时,将调用handleEvent方法。您可以测试.type以查看它是哪个事件。

this中的handleEvent值将成为对象,可让您直接访问其方法。


如果您使用构造函数,此技术也很有用,因为您可以使用其他方法对handleEvent进行原型设计,并且继承该原型的所有对象都将实现 EventListener 界面。


如果你要使用一个闭包,我会将关闭的变量放在Game.Router函数中,这样任何和所有方法都可以利用它。

Game.Router = function() {
    var self = this;
    return self = {
        init: function() { // using 'self' in case 'init' becomes detached
            window.addEventListener('hashchange', self.route, false);
        },

        route: function(e) {
            // use 'self' to refer to the object
        },

        toggleView: function(viewID) {
            // use 'self' to refer to the object
        }
    }
}();

答案 1 :(得分:4)

我希望the link I gave能够明确解决您的问题。

为了不提供通常的闭包解决方案,这里更简单(与IE8不兼容):

 window.addEventListener('hashchange', this.route.bind(this), false);

答案 2 :(得分:2)

你需要使用一个闭包:

route: (function(context){
    return function(e){

        //your original function, but with all
        //references to this changed to
        //context

    }
})(this),