警告:长(ish)答案
这是直接从我在公司内部维基上写的一篇文章中复制的:
问题:如何在循环中正确使用闭包?快速回答:使用函数工厂。
  for (var i=0; i<10; i++) {
    document.getElementById(i).onclick = (function(x){
      return function(){
        alert(x);
      }
    })(i);
  }
或更容易阅读的版本:
  function generateMyHandler (x) {
    return function(){
      alert(x);
    }
  }
  for (var i=0; i<10; i++) {
    document.getElementById(i).onclick = generateMyHandler(i);
  }
这常常让不熟悉 javascript 或函数式编程的人感到困惑。这是误解了什么是闭包的结果。
闭包不仅仅传递变量的值,甚至是对变量的引用。闭包捕获变量本身!以下代码说明了这一点:
  var message = 'Hello!';
  document.getElementById('foo').onclick = function(){alert(message)};
  message = 'Goodbye!';
单击元素“foo”将生成一个带有消息的警告框:“再见!”。因此,在循环中使用一个简单的闭包将导致所有闭包共享相同的变量,并且该变量将包含循环中分配给它的最后一个值。例如:
  for (var i=0; i<10; i++) {
    document.getElementById('something'+i).onclick = function(){alert(i)};
  }
单击所有元素时将生成一个数字为 10 的警报框。事实上,如果我们现在这样做,i="hello";所有元素现在都会生成一个“你好”警报!变量 i 在十个函数加上当前函数/范围/上下文中共享。把它想象成一种只有相关函数才能看到的私有全局变量。
我们想要的是该变量的实例,或者至少是对变量的简单引用,而不是变量本身。幸运的是,javascript 已经有一种传递引用(对于对象)或值(对于字符串和数字)的机制:函数参数!
当在 javascript 中调用一个函数时,如果它是一个对象,则该函数的参数通过引用传递,如果它是一个字符串或数字,则通过值传递。这足以打破闭包中的变量共享。
所以:
  for (var i=0; i<10; i++) {
    document.getElementById(i).onclick =
      (function(x){ /* we use this function expression simply as a factory
                       to return the function we really want to use: */
        /* we want to return a function reference
           so we write a function expression*/
        return function(){
          alert(x); /* x here refers to the argument of the factory function
                       captured by the 'inner' closure */
        }
      /* The brace operators (..) evaluates an expression, in this case this
         function expression which yields a function reference. */
      })(i) /* The function reference generated is then immediately called()
               where the variable i is passed */
  }