admin管理员组文章数量:1429151
I've generalized my lack of understanding of the situation to this small problem. Here's what I think I know so far:
I have an object myDog
(a global variable). Dog
has a member variable el
that is an html element; because it's an element, I can add event listeners to it. So, when you click on myDog.el
, it logs to the console the values of this.name
and myDog.name
. As expected because of scope, this.name
is undefined and myDog.name
is 'tye'. this
inside of Dog.speak
when invoked by the click event listener refers to the element that was clicked, the member variable el
, not the object Dog
. Since myDog
is a global variable, it's able to pick back up regardless of the function's scope and get to myDog.name
just fine.
See code below:
function Dog(name,id) {
this.name = name ? name : "spot";
this.id = id ? id : "dog";
this.el = document.getElementById(this.id); // given there is a div with a matching
this.el.addEventListener("click",this.speak); // ignore IE for simplicity (attachEvent has its own 'this' scope issues)
}
Dog.prototype = {
speak: function() {
console.log("this.name: "+this.name+"\nmyDog.name: "+myDog.name);
}
};
var myDog = new Dog("tye","dog1");
So... my questions are
1) What are some strategies for attaching objects to html elements, so that I can go from this.el
back to myDog
(this.el
's owner) without myDog
being a global variable?
2) Are global variables in this case a necessary evil? And if so, what are so good strategies in this case to gracefully use them? For example, what if I wanted 100 dogs instantiated? How would I handle all those global variables in Dog.speak
?
Here's a jsfiddle version if you want to play with it: /
I've generalized my lack of understanding of the situation to this small problem. Here's what I think I know so far:
I have an object myDog
(a global variable). Dog
has a member variable el
that is an html element; because it's an element, I can add event listeners to it. So, when you click on myDog.el
, it logs to the console the values of this.name
and myDog.name
. As expected because of scope, this.name
is undefined and myDog.name
is 'tye'. this
inside of Dog.speak
when invoked by the click event listener refers to the element that was clicked, the member variable el
, not the object Dog
. Since myDog
is a global variable, it's able to pick back up regardless of the function's scope and get to myDog.name
just fine.
See code below:
function Dog(name,id) {
this.name = name ? name : "spot";
this.id = id ? id : "dog";
this.el = document.getElementById(this.id); // given there is a div with a matching
this.el.addEventListener("click",this.speak); // ignore IE for simplicity (attachEvent has its own 'this' scope issues)
}
Dog.prototype = {
speak: function() {
console.log("this.name: "+this.name+"\nmyDog.name: "+myDog.name);
}
};
var myDog = new Dog("tye","dog1");
So... my questions are
1) What are some strategies for attaching objects to html elements, so that I can go from this.el
back to myDog
(this.el
's owner) without myDog
being a global variable?
2) Are global variables in this case a necessary evil? And if so, what are so good strategies in this case to gracefully use them? For example, what if I wanted 100 dogs instantiated? How would I handle all those global variables in Dog.speak
?
Here's a jsfiddle version if you want to play with it: http://jsfiddle/chadhutchins/Ewgw5/
Share Improve this question asked Dec 1, 2011 at 5:06 Chad HutchinsChad Hutchins 4843 silver badges10 bronze badges 3- 1 One of the most mon ways of getting around scope problems with this is assigning 'this' to a variable at the start of a function...self will always refer to the original this. – Pastor Bones Commented Dec 1, 2011 at 5:09
- Thanks for the response, but will you explain that a bit further? How can I use that technique in the example above. – Chad Hutchins Commented Dec 1, 2011 at 5:16
- I also do as Pastor Bones said – MilkyWayJoe Commented Dec 1, 2011 at 5:16
3 Answers
Reset to default 6"1) What are some strategies for attaching objects to html elements..."
Since you're using .addEventListener()
, I'd suggest taking advantage of a feature of it that few people seem to know about... making your Dog
object implement the EventListener
interface.
This establishes a very clean relationship between your Dog
data and its associated element.
Only minor changes are required. Code first... explanation below.
DEMO: http://jsfiddle/Ewgw5/1/
function Dog(name,id) {
this.name = name ? name : "spot";
this.id = id ? id : "dog";
this.el = document.getElementById(this.id);
// ---------------------------------v----no function!
this.el.addEventListener("click", this);
}
Dog.prototype = {
// Implement the `EventListener` interface
handleEvent: function(event) {
switch (event.type) {
case "click": return this.speak();
}
},
speak: function() {
console.log("this.name: "+this.name+"\nmyDog.name: "+myDog.name);
}
};
var myDog = new Dog("tye","dog1");
So all I did was pass this
in the constructor to addEventListener()
instead of passing a function, and then I added a handleEvent()
method to Dog.prototype
.
Now when a "click"
event occurs, it will invoke the handleEvent()
method. The value of this
in that method will be your Dog
instance. So from there you can call whatever method(s) you need.
Because you made the element a property of this
, you can access the element via this.el
. But that's technically not even necessary, since the element is also available via the event
object as event.currentTarget
.
"2) Are global variables in this case a necessary evil..."
Thankfully no!
This behavior should be part of your shim for .addEventListener()
.
You can try something like this:
function Dog(name,id) {
var self = this; // <---- NEW BIT saving a reference to this
this.name = name || "spot"; // <-- unrelated tidy-up to use || instead of ?:
this.id = id || "dog";
this.el = document.getElementById(this.id); // given there is a div with a matching
this.el.addEventListener("click",function(){ self.speak(); });
// ignore IE for simplicity (attachEvent has its own 'this' scope issues)
}
Through the magic of closures the anonymous function I've added within addEventListener()
has access to the scope of the containing function even after the containing function returns, so it is able to use self
which holds a reference to the original object saved from this
when Dog()
was called as a constructor.
EDIT: Sorry, I didn't directly address the questions you numbered (1) and (2), but as you can see you don't need global variables to fix this this issue. With the technique I described you could instantiate 100 dogs and they'd all work. (Well, they'd all speak anyway: they'd all work if you added Dog.prototype.work = function() { }
.)
https://developer.mozilla/en/JavaScript/Reference/Global_Objects/Function/bind
this.el.addEventListener("click", this.speak.bind(this));
This way is preferable because it doesn't require allocating a scope in order to pass the binding. Scope allocation is one of the more costly things in JS.
本文标签:
版权声明:本文标题:javascript - Dealing with Scope in Object methods containing 'this' keyword called by Event Listeners- Stack Ove 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1745532501a2662124.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论