我可以通过“新”吗? addEventListener 的匿名函数
我使用这样的代码将参数传递给事件处理函数。但是,在这种特殊情况下,循环会引起问题。在所有 activeVisual 调用中只能访问最后一个 linkTags[i]。这与传递参数的匿名函数在整个循环中是同一个这一事实有关。
for (var i = 0; i < linkTags.length; i++) {
addCrossEvent(linkTags[i], "click", launchLink);
addCrossEvent(linkTags[i], "mousedown",
function(evt) {
activeVisual(evt, linkTags[i]);
});
}
现在,我记得尝试在匿名函数声明之前添加 new ,如下所示:
for (var i = 0; i < linkTags.length; i++) {
addCrossEvent(linkTags[i], "click", launchLink);
addCrossEvent(linkTags[i], "mousedown",
new function(evt) {
activeVisual(evt, linkTags[i]);
});
}
它不起作用。 activeVisual 永远不会被调用。有人可以向我解释一下为什么以及如何让它发挥作用吗?
更新最终解决方案
感谢下面的所有回复,我的工作代码现在看起来像这样:
// Function that provides pass of event handling parameters with separate copy in each loop
function callbackHandler(index) {
return function(evt) {
activeVisual(evt, linkTags[index]);
}
}
...
for (var i = 0; i < linkTags.length; i++) {
...
addCrossEvent(linkTags[i], "mousedown", callbackHandler(i));
}
I use such code to pass arguments to event handler functions. But, in this particular case the loop is causing problems. Only the last linkTags[i] is accesible in all activeVisual calls. This has to do with the fact that the anonymous function that passes the argument is one and the same for the entire loop.
for (var i = 0; i < linkTags.length; i++) {
addCrossEvent(linkTags[i], "click", launchLink);
addCrossEvent(linkTags[i], "mousedown",
function(evt) {
activeVisual(evt, linkTags[i]);
});
}
Now, I remember trying to add new before the anonymous function declaration like this:
for (var i = 0; i < linkTags.length; i++) {
addCrossEvent(linkTags[i], "click", launchLink);
addCrossEvent(linkTags[i], "mousedown",
new function(evt) {
activeVisual(evt, linkTags[i]);
});
}
It did not work. The activeVisual never gets called. Can somebody explain to me why and how can I make it work, please?
UPDATE FINAL SOLUTION
Thanks to all responses below my WORKING code now looks like this:
// Function that provides pass of event handling parameters with separate copy in each loop
function callbackHandler(index) {
return function(evt) {
activeVisual(evt, linkTags[index]);
}
}
...
for (var i = 0; i < linkTags.length; i++) {
...
addCrossEvent(linkTags[i], "mousedown", callbackHandler(i));
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您需要这样做:
问题在于迭代器变量
i
在每次迭代时都会发生变化,并且传递了它的引用,但i
的值不会被复制。以这种方式将其作为参数传递给包装函数,将导致复制,并且它将在该特定迭代中接收实际值。You need to do this:
The issue is with the iterator variable
i
which changes at each iteration, and a reference is passed of it, the value ofi
is not copied. Passing it this way as a parameter to a wrapper function, will cause a copy and it will receive the actual value at that particular iteration.为了完整起见,这里解释了为什么您使用
new
的方式不起作用:当您使用
new
调用函数时,该函数会生成一个空对象(您可以参考到函数内部的this
并继承自函数原型)并返回它。因此,您实际上不会传递函数作为回调处理程序,而是传递函数返回的对象。
只要对象实现
EventListner
接口,以便可用作事件处理程序。如果你这样做,你可以使用你的代码进行一些修改:这实际上类似于@Luca的答案,因为
i
的值是在对象创建时捕获的。上面的代码实际上与:也就是说,我发现返回函数的立即函数的用法更容易阅读,并且我认为使用函数作为事件处理程序而不是对象也更常见。
工作演示
For completeness, here is an explanation why your way of using
new
does not work:When you call a function with
new
, the function generates an empty object (which you can refer to withthis
inside the function and which inherits from the functions prototype) and returns it.So you actually don't pass a function as callback handler, but the object returned by the function.
This is not a problem as long as the object implements the
EventListner
interface in order to be usable as event handler. If you do this, you could use your code with some modification:This is actually similar to @Luca's answer, because the value of
i
is captured upon object creation. The upper code is actually identical to:That said I find the usage of an immediate function that returns a function easier to read and I think using a function as event handler instead of an object is more common too.
Working DEMO