最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

firebug - Why aren't these two bits of JavaScript equivalent? - Stack Overflow

programmeradmin2浏览0评论

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 unment out the loop and ment 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>

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 unment out the loop and ment 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>
Share Improve this question edited Jul 20, 2010 at 10:01 Daniel Vassallo 345k72 gold badges512 silver badges446 bronze badges asked Jul 20, 2010 at 6:22 fastmultiplicationfastmultiplication 3,1011 gold badge34 silver badges39 bronze badges 2
  • Please start with fixing your HTML. You have two unclosed <p> tags. – Māris Kiseļovs Commented Jul 20, 2010 at 6:24
  • You should declare your variables unless you want them to be global variables. var names = ['one', 'two', 'three'];, for (var k in names) {, var id. – Matt Commented Jul 20, 2010 at 6:35
Add a ment  | 

2 Answers 2

Reset to default 12

You would be having a very mon 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 the id variable will be left pointing to the value of the last element of the names 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:

  • Mozilla Dev Center: Working with Closures

You could solve this with even more closures, using a function factory:

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));
}

You could also inline the above function factory as follows:

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));
}

Any yet another solution could be as @d.m suggested in another answer, enclosing each iteration in its own scope:

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

for (k = 0; k < names.length; k++) {
  (function() {
    var id = names[k];
    $("#" + id).mouseenter(function () { console.log(id) });
  })();
}

Although not related to this problem, it is generally remended to avoid using a for in loop to iterate over the items of an array, as @CMS pointed out in a ment below (Further reading). In addition, explicitly terminating your statements with a semicolon is also considered a good practice in JavaScript.

This happens because when the code of the anonymous function function(){console.log(id)} is executed, the value of id is three indeed.

To can use the following trick to enclose the value on each loop iteration into the anonymous callback scope:

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

评论列表(0)

  1. 暂无评论