为什么不';这两位JavaScript不是等价的吗?

为什么不';这两位JavaScript不是等价的吗?,javascript,firebug,closures,jquery,Javascript,Firebug,Closures,Jquery,在jquery 1.4.2,ff 3.6.6中: 下面的代码生成三个div,它们将消息写入firebug控制台,正如您所期望的那样。但是,如果您取消对循环的注释,并手动注释掉3行,则它不起作用-将鼠标移到任何div上会导致“三”写入控制台 为什么这两种方法有什么不同?在每个元素中,使用选择器查找元素并向其添加事件 <head> <script type="text/javascript" src="/media/js/jquery.js"></script>

在jquery 1.4.2,ff 3.6.6中:

下面的代码生成三个div,它们将消息写入firebug控制台,正如您所期望的那样。但是,如果您取消对循环的注释,并手动注释掉3行,则它不起作用-将鼠标移到任何div上会导致
“三”
写入控制台

为什么这两种方法有什么不同?在每个元素中,使用选择器查找元素并向其添加事件

<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>

$(文档).ready(函数(){
$(“#一”).mouseenter(函数(){console.log(“一”)})
$(“#两个”).mouseenter(函数(){console.log(“两个”)})
$(“#三”).mouseenter(函数(){console.log(“三”)})
//姓名=['1'、'2'、'3'];
//for(名称为k){
//id=名称[k]
//$(“#”+id).mouseenter(函数(){console.log(id)})
//  }
})
一个
两个

您将在
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));
}
函数makeMouseEnterCallback(id){
返回函数(){
console.log(id);
};  
}
// ...
变量id,k,
姓名=['1'、'2'、'3'];
对于(k=0;k
您还可以按如下方式内联上述函数工厂:

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));
}
var id,k,
姓名=['1'、'2'、'3'];
对于(k=0;k
任何另一种解决方案都可以是,将每个迭代都包含在自己的范围内:

var k, 
    names = ['one','two','three'];

for (k = 0; k < names.length; k++) {
  (function() {
    var id = names[k];
    $("#" + id).mouseenter(function () { console.log(id) });
  })();
}
var k,
姓名=['1'、'2'、'3'];
对于(k=0;k

尽管与此问题无关,但通常建议避免使用
for in
循环来迭代数组的项,如下面的注释()所指出的。此外,在JavaScript中,用分号显式终止语句也是一种很好的做法。

这是因为当匿名函数
function(){console.log(id)}
的代码被执行时,
id
的值实际上是
3

您可以使用以下技巧将每个循环迭代中的值包含到匿名回调范围中:

names=['one', 'two', 'three'];
for (var k in names) {
    (function() {
        var id = names[k];
        $("#"+id).mouseenter(function(){ console.log(id) });
    })();
}

请从修复HTML开始。您有两个未关闭的标记。您应该声明变量,除非您希望它们是全局变量<代码>变量名称=['1'、'2'、'3']
for(名称中的var k){
var id
。回答得好(+1),但如果您向他演示如何在循环中为id创建新字符串,那就更好了。此外,尽管这不是问题,但我永远不会厌倦建议避免使用
for in
语句进行“迭代”在数组对象上。@Bernhard:谢谢……我将用几个解决方案更新我的答案:)小的输入错误、第一个示例中的函数名以及第二个示例中匿名函数的立即调用都丢失了。它不起作用,因为
id
未声明,它将成为全局对象的属性(
window.id
)。您需要将其绑定到新的变量环境(使用
var
!):不客气。还要注意,
k
将成为全局的,
for-in
语句的目的并不是迭代数组对象的索引,它的目的是枚举对象属性。@CMS,噢,该死,对不起;刚刚醒来,还不在这个世界上。我知道for-in;我个人更喜欢<代码>for(vari=names.length-1;i>=0;i--)
循环在本例中,但正如我前面所说的,我只是复制了快速乘法的代码。:没问题!是的,任何连续循环,如果迭代顺序不重要,则使用反向循环,例如
vari=names.length;而(i--){/**
就足够了。干杯!