为什么这两个JavaScript不等同?

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中的一种很好的做法.