我把这种情况的缺乏理解归结为这个小问题。到目前为止,我认为这就是我所知道的:
我有一个对象myDog
(一个全局变量)。 Dog
有一个成员变量el
,它是一个html元素;因为它是一个元素,我可以添加事件监听器。因此,当您点击myDog.el
时,它会在控制台中记录this.name
和myDog.name
的值。正如预期的那样,范围this.name
未定义且myDog.name
为'tye'。当由click事件侦听器调用时,this
内的Dog.speak
引用被单击的元素,即成员变量el
,而不是对象Dog
。由于myDog
是一个全局变量,因此无论函数的范围如何,它都能够进行备份,并且myDog.name
就好了。
见下面的代码:
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");
所以...我的问题是
1)将对象附加到html元素的策略是什么,以便我可以从this.el
返回myDog
(this.el
的所有者)而不myDog
是一个全球变量?
2)在这种情况下全局变量是否是必要的邪恶?如果是这样,在这种情况下优雅使用它们的优秀策略是什么?例如,如果我想要100只狗实例化怎么办?我如何处理Dog.speak
中的所有全局变量?
如果你想玩它,这是一个jsfiddle版本:http://jsfiddle.net/chadhutchins/Ewgw5/
答案 0 :(得分:5)
" 1)将对象附加到html元素的策略是什么......"
由于您正在使用.addEventListener()
,我建议您充分利用其中很少有人知道的功能......让您的Dog
对象实现{ {1}}界面。
这在您的EventListener
数据及其相关元素之间建立了非常干净的关系。
只需要进行细微更改。代码优先......解释如下。
DEMO: http://jsfiddle.net/Ewgw5/1/
Dog
所以我所做的就是将构造函数中的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");
传递给this
而不是传递函数,然后我将addEventListener()
方法添加到handleEvent()
。
现在发生Dog.prototype
事件时,它将调用"click"
方法。该方法中handleEvent()
的值将是您的this
实例。所以从那里你可以调用你需要的任何方法。
由于您将元素设为Dog
的属性,因此您可以通过this
访问该元素。但这在技术上甚至没有必要,因为该元素也可以通过this.el
对象event
获得。
" 2)在这种情况下,全局变量是否是必要的罪恶......"
谢天谢地!
此行为应该是event.currentTarget
的垫片的一部分。
答案 1 :(得分:3)
您可以尝试这样的事情:
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)
}
通过闭包的魔力,我在addEventListener()
中添加的匿名函数即使在包含函数返回后也可以访问包含函数的范围,因此它可以使用self
当this
被称为构造函数时,它保存对从Dog()
保存的原始对象的引用。
Dog.prototype.work = function() { }
,他们都会工作。)
答案 2 :(得分:1)
https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/bind
this.el.addEventListener("click", this.speak.bind(this));
这种方式更可取,因为它不需要分配范围以传递绑定。范围分配是JS中成本较高的事情之一。