我正在为我正在开发的游戏编写一个类,它根据页面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”上下文会发生变化吗?
答案 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),