为什么 JavaScript 的这两部分不等价?
在 jquery 1.4.2、ff 3.6.6 中:
以下代码生成三个 div,它们按照您的预期将消息写入 firebug 控制台。但是,如果您取消注释掉循环并注释掉手动执行的 3 行,则它将不起作用 - 将鼠标悬停在任何 div 上都会导致 "third"
被写入控制台。
为什么这两种方法有什么不同?在每个元素中,您都使用选择器来查找元素并向其添加事件。
<head>
<script type="text/javascript" src="/media/js/jquery.js"></script>
<script>
$( document ).ready( function() {
$("#one").mouseenter(function(){console.log("one")})
$("#two").mouseenter(function(){console.log("two")})
$("#three").mouseenter(function(){console.log("three")})
// names=['one','two','three'];
// for (k in names){
// id=names[k]
// $("#"+id).mouseenter(function(){console.log(id)})
// }
})
</script>
</head>
<body>
<span id="one">ONE</span>
<p><span id="two">TWO</span></p>
<p><span id="three">THREE</span></p>
</body>
in jquery 1.4.2, ff 3.6.6:
The following code produces three divs, which write messages to the firebug console as you would expect. However, if you uncomment out the loop and comment out the 3 lines doing it manually, it doesn't work - mousing over any of the divs results in "three"
being written to the console.
Why are these two methods any different than each other? In each one you use a selector to find the element and add an event to it.
<head>
<script type="text/javascript" src="/media/js/jquery.js"></script>
<script>
$( document ).ready( function() {
$("#one").mouseenter(function(){console.log("one")})
$("#two").mouseenter(function(){console.log("two")})
$("#three").mouseenter(function(){console.log("three")})
// names=['one','two','three'];
// for (k in names){
// id=names[k]
// $("#"+id).mouseenter(function(){console.log(id)})
// }
})
</script>
</head>
<body>
<span id="one">ONE</span>
<p><span id="two">TWO</span></p>
<p><span id="three">THREE</span></p>
</body>
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您将在 一个非常常见的闭包问题代码>for in循环。
闭包中包含的变量共享相同的单一环境,因此当调用 mouseenter 回调时,循环将运行完毕,并且 id 变量将保持指向为
names
数组最后一个元素的值。如果您不熟悉闭包的工作原理,这可能是一个相当棘手的话题。您可能需要查看以下文章以获取简要介绍:
您可以使用函数工厂通过更多闭包来解决此问题:
您还可以按如下方式内联上述函数工厂:
任何其他解决方案都可以是 @dm 在另一个答案中建议,将每个迭代包含在自己的范围内:
虽然与对于这个问题,通常建议避免使用
for in
循环来迭代数组的项目,如 @CMS 在下面的评论中指出(进一步阅读)。此外,在 JavaScript 中,用分号显式终止语句也被认为是一种很好的做法。You would be having a very common closure problem in the
for in
loop.Variables enclosed in a closure share the same single environment, so by the time the
mouseenter
callback is called, the loop will have run its course and theid
variable will be left pointing to the value of the last element of thenames
array.This can be quite a tricky topic, if you are not familiar with how closures work. You may want to check out the following article for a brief introduction:
You could solve this with even more closures, using a function factory:
You could also inline the above function factory as follows:
Any yet another solution could be as @d.m suggested in another answer, enclosing each iteration in its own scope:
Although not related to this problem, it is generally recommended to avoid using a
for in
loop to iterate over the items of an array, as @CMS pointed out in a comment below (Further reading). In addition, explicitly terminating your statements with a semicolon is also considered a good practice in JavaScript.出现这种情况是因为执行匿名函数
function(){console.log(id)}
的代码时,id
的值为Three
确实如此。可以使用以下技巧将每次循环迭代的值包含到匿名回调范围中:
This happens because when the code of the anonymous function
function(){console.log(id)}
is executed, the value ofid
isthree
indeed.To can use the following trick to enclose the value on each loop iteration into the anonymous callback scope: