fas*_*ion 3 javascript jquery firebug closures
在jquery 1.4.2中,ff 3.6.6:
以下代码生成三个div,它们会像您期望的那样将消息写入firebug控制台.但是,如果您取消注释循环并注释掉手动执行它的3行,则它不起作用 - 将鼠标悬停在任何div上会导致"three"写入控制台.
为什么这两种方法彼此不同?在每一个中,您使用选择器来查找元素并向其添加事件.
<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>
Run Code Online (Sandbox Code Playgroud)
Dan*_*llo 12
你会在循环中遇到一个非常常见的闭包问题for in.
封闭在闭包中的变量共享相同的单个环境,因此在mouseenter调用回调时,循环将运行并且id变量将指向names数组的最后一个元素的值.
如果您不熟悉闭包的工作方式,这可能是一个非常棘手的主题.您可能需要查看以下文章以获得简要介绍:
你可以使用函数工厂解决这个问题:
function makeMouseEnterCallback (id) {
return function() {
console.log(id);
};
}
// ...
var id, k,
names = ['one','two','three'];
for (k = 0; k < names.length; k++) {
id = names[k];
$("#" + id).mouseenter(makeMouseEnterCallback(id));
}
Run Code Online (Sandbox Code Playgroud)
您还可以按如下方式内联上述函数工厂:
var id, k,
names = ['one','two','three'];
for (k = 0; k < names.length; k++) {
id = names[k];
$("#" + id).mouseenter((function (p_id) {
return function() {
console.log(p_id);
};
})(id));
}
Run Code Online (Sandbox Code Playgroud)
任何另一个解决方案都可以像@dm在另一个答案中建议的那样,将每个迭代包含在自己的范围内:
var k,
names = ['one','two','three'];
for (k = 0; k < names.length; k++) {
(function() {
var id = names[k];
$("#" + id).mouseenter(function () { console.log(id) });
})();
}
Run Code Online (Sandbox Code Playgroud)
尽管与此问题无关,但通常建议避免使用for in循环迭代数组的项,如下面的注释中指出的@CMS(进一步阅读).此外,使用分号显式终止语句也被认为是JavaScript中的一种很好的做法.