admin管理员组文章数量:1356585
I'm currently writing a class for a game I'm working on that controls application routing based on hash changes in the page URL.
My problem is that the context of "this" changes to "window" after attaching the main routing function to the hashchange event.
Here is the code so far:
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 = '';
}
}
}
}
}();
When I try and call this.toggleView in the route function's switch statement, it turns out that "this" has changed from Game.Router to window. The problem can be fixed by replacing this.toggleView with Game.Router.toggleView, but this isn't ideal.
Could someone please help me understand why the "this" context changes after adding the event listener?
I'm currently writing a class for a game I'm working on that controls application routing based on hash changes in the page URL.
My problem is that the context of "this" changes to "window" after attaching the main routing function to the hashchange event.
Here is the code so far:
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 = '';
}
}
}
}
}();
When I try and call this.toggleView in the route function's switch statement, it turns out that "this" has changed from Game.Router to window. The problem can be fixed by replacing this.toggleView with Game.Router.toggleView, but this isn't ideal.
Could someone please help me understand why the "this" context changes after adding the event listener?
Share Improve this question edited Nov 23, 2012 at 15:42 DarkAjax 16.2k11 gold badges57 silver badges66 bronze badges asked Nov 23, 2012 at 15:40 thesonglessbirdthesonglessbird 5701 gold badge7 silver badges16 bronze badges 2- 2 This is one of the most duplicated question on SO. Rather than looking for an exact duplicate I can suggest to read this : stackoverflow./questions/1085674/… – Denys Séguret Commented Nov 23, 2012 at 15:44
- Yeah, I had a feeling it might be. Searching turned up nothing useful though... – thesonglessbird Commented Nov 23, 2012 at 15:59
3 Answers
Reset to default 4I hope the link I gave makes the reason of your problem clear.
In order not to give the usual closure solution, here's a simpler one (not patible with IE8-) :
window.addEventListener('hashchange', this.route.bind(this), false);
Since you're using addEventListener
, just add a handleEvent
method to the object, and pass the object instead of the handler.
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
}
}
}();
What this does is that it causes the object to implement the EventListener interface. Therefore the object itself bees a valid event handler, and can be passed to addEventListener
instead of a function.
So when any even occurs, the handleEvent
method will be invoked. You can test for the .type
to see which event it was.
The this
value in handleEvent
will be the object, which gives you direct access to its methods.
This technique is also useful if you're using a constructor function, because you can just prototype the handleEvent
with the other methods, and all objects that inherit that prototype will implement the EventListener interface.
If you were to use a closure, I'd put the closed-over variable in the Game.Router
function so any and all methods can take advantage of it.
Game.Router = function() {
var self = this;
return self = {
init: function() { // using 'self' in case 'init' bees 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
}
}
}();
You need to use a closure:
route: (function(context){
return function(e){
//your original function, but with all
//references to this changed to
//context
}
})(this),
本文标签: javascriptContext of this changing when using windowaddEventListener inside classStack Overflow
版权声明:本文标题:javascript - Context of this changing when using window.addEventListener inside class - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1744028407a2578458.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论