2008年4月1日星期二

你必须记住“这个”

在全世界所有网站上的所有科技博客中,你走进了我的。。。

如果你在面向JavaScript的新闻组中闲逛喜欢 这些无论时间长短,你最终都会看到这个问题的一些变化:

嘿,为什么这个不行?
函数MyWidget(名称)
{
this.name=名称;
this.element=空;
}
MyWidget.prototype.showName=函数()
{
alert(“名称为”+this.name);
}
MyWidget.prototype.hookElement=函数(元素)
{
this.element=元素;
事件.观察(this.element,'click',this.showName);
}
功能测试()
{
var小部件;

widget=新的MyWidget(“测试名称”);
widget.hookElement(document.getElementById('testDiv'));
}
“testDiv”是文档中的一个div,我知道在加载DOM之前我没有调用test()函数,所以为什么当我单击div时,我会得到消息“the name is undefined”?!
(一如既往,我使用一些方便语法用于连接事件处理程序。)

OP(原版海报)甚至可以继续:
我甚至尝试将observe()行改为:
Event.observe(this.element,‘click’,function()){
this.showName();
});
因为我听说你必须这样做,但更糟糕的是,它会导致错误,说this.showName()不是函数?!
这里的问题是OP还没有完全理解“this”及其在JavaScript世界中的特殊作用。

我谈了一点“这个”在这里,但我想发表一篇文章,重点讨论上面的OP和我们中的许多人一样陷入的特定陷阱(忘记“这一点”)以及您如何应对。

让我们先看看这条线有什么问题:
Event.oserve(this.element,'click',this.showName);//错了
JavaScript没有方法(参见上面的链接),因此this.show名称只返回一个函数引用,与OP想要绑定到元素的实例完全没有连接。它只是一个函数。(正确使用,这是一个强大的功能,但在这种情况下,它给OP带来了一些麻烦。)回想一下节目名称定义如下:
MyWidget.prototype.showName=函数()
{
alert(“名称为”+this.name);
}
在代码中,“this”不是由设置事件处理程序的位置决定的,而是由函数的调用方式决定的。最有可能的是,“this”将引用被单击的元素(“testDiv”),因为现代浏览器在事件处理程序中将与事件相关的元素用作“this“。因此,this.name(此名称)未定义,除非相关元素碰巧具有名称属性。

因此,为了获得预期效果,您必须将调用包装到this.showName()所以当代码被执行时,“this”就是MyWidget实例——你必须记住“this(这)”。这可能是OP在尝试此操作时听到的:
Event.observe(this.element,‘click’,function()){
this.showName();
}); // 还是错了
这越来越近了,事实上,如果我们使用一个变量来引用小部件而不是“This”,它会起作用,但因为它是“This”,我们实际上仍然有与以前完全相同的问题:当调用事件处理程序时,“This”是元素,而不是小部件,因此没有显示名称()要调用的函数。

那么我们该怎么处理呢?好吧,我看到了一种重写挂钩元素功能:
MyWidget.prototype.hookElement=函数(元素)
{
变量自身;

this.element=元素;
自我=此;
Event.observe(this.element,‘click’,function()){
self.showName();
});
}
这是因为我们不再在事件处理程序中使用“This”,而是使用“self”(事件处理程序可以访问“self“,因为它是一个闭包;更多在这里). 所以这个解决方案是可行的。不过,我不能说我喜欢它。只是感觉。。。我想是有点怪。但它仍然有效,虽然第一次看起来有点滑稽,但如果你熟悉这个习语,你以后就会读过它。您只需要确保闭包不会不必要地保留函数中其他地方的其他大量数据。

但就个人而言,我更喜欢使用可重用的“绑定”函数。许多JavaScript工具包都有这些(例如Prototype的绑定()bindAsEventListener()),但并不复杂:
函数绑定(f,obj)
{
返回函数(){
返回f.apply(obj,参数);
};
}
这是一个函数工厂:它创建的函数在调用时将调用给定的函数,并将给定的对象设置为“This”(使用JavaScript的便利性应用()功能;插入您自己的“基本要素适用“这里开玩笑)。现在我们可以重写OP挂钩元素类似这样的功能(与顶部粗体的原始功能不同):
MyWidget.prototype.hookElement=函数(元素)
{
this.element=元素;
事件观察(this.element,‘click’,
绑定(this.show名称,本)
);
}
您可能想知道为什么我们必须两次指定“this”。记住this.show名称只返回一个函数引用,没有任何关于实例的内容(我们可以替换this.show名称在上面的我的小工具.prototype.showName如果我们喜欢的话)。如果我们愿意绑定()为了知道要将函数绑定到哪个实例,我们必须指定它——最后。

就这样!现在,事件处理程序按照OP的预期工作。

3条评论:

T.J.克劳德说。。。

进一步阅读:克里斯托夫·波特纽夫(Christophe Porteneuve)关于装订

gnrlbzik公司说。。。

另一篇很棒的文章。很高兴我保存了它:)

未知说。。。

谢谢你的文章,这是一个很好的地方