以下是本人的一些看法,谢谢大家,欢迎砖头循环内使用闭包的其实要根据作用域来解释首先js中是没有“块状作用域”的,请看下面java例子
     //scope1 作用域1
     for (int i = 0; i < 10; i++){
        //scope2 作用域2
         String str = "123";
     
     }     
     Systen.out.print(i);
     Systen.out.print(str);
  
在有块状作用域的语言中,scope1与scope2是不同的作用域,所以
Systen.out.print(i);与Systen.out.print(str);都应该报错,i,str未定义
  
但js并没有块状作用域,看以下例子
//scope1 作用域1
     for (var i = 0; i < 10; i++){
         //scope2 作用域2
         var str = "123";
     }
          
     alert(i);
     alert(str);在js中scope1与scope2是同级的,所以alert(i)打印出10, alert(str)打印出123
不单for是这种情况,if,while等都是一样的,上面例子等同于//scope1 作用域1
     var i = 0;
     var str;
     for (; i < 10; i++){
         //scope2 作用域2
         str = "123";
     }
          
     alert(i);
     alert(str);
  
所以
//scope1 作用域1
     var els = document.getElementsByTagName("li");
     for (var i = 0, j = els.length; i < j; i++){
         //scope2 作用域2
         var el = els[i];
        el.onclick = function(){
            //scope3 作用域3
            alert(i);
        }
     }
其实等同于//scope1 作用域1
     var els = document.getElementsByTagName("li");
     var i = 0, j = els.length;     for (; i < j; i++){
         //scope2 作用域2
         var el = els[i];
        el.onclick = fn;
     }     function fn(){
        //scope3 作用域3
        alert(i); //当执行onclick时,i已经循环完毕
     }这时大家会想,scope3与scope1,scope2是不同一个作用域,为什么还能打印出来,
这是因为js有作用域链这种思想,当i在scope3找不到的时候,会向上级作用域scope1访问,如果类推,
直到scope1访问到,所以这里的i其实就是scope1中的i,这时i已经是循环完毕了。
因此要避免这种情况,我们就要从它的作用域入手了,请看改造例子//scope1 作用域1
     var els = document.getElementsByTagName("li");
     for (var i = 0, j = els.length; i < j; i++){
         //scope2 作用域2
         var el = els[i];
        el.onclick = function(i){
            //scope3 作用域3
            return function(){
                //scope4 作用域4
                alert(i)
            }
        }(i)
     }因为作用域链,alert(i)访问scope4没有,向上级scope3访问,它发现i已经由(i)传进来赋值了,
所以alert(i)这里的i其实是scope3作用域中的i,而并不是scope1中的i而如果我们改成这样
//scope1 作用域1
     var els = document.getElementsByTagName("li");
     for (var i = 0, j = els.length; i < j; i++){
         //scope2 作用域2
         var el = els[i];
        
        el.onclick = function(){ //这里没有声明形参
            //scope3 作用域3
            return function(){
                //scope4 作用域4
                alert(i)
            }
        }(i)
     }alert(i)中的i访问到的就是scope1的i,打印出来的还是循环完毕后的i...

解决方案 »

  1.   


    看了楼主说的后2段,还是说说俺的理解。
    倒数第2段改为这样好理解一些:
    el.onclick = function(k){
                return function(){
                    alert(k)
                }
            }(i)说说俺的一些理解:
    click右边应该是个functionHandle,绑定某个函数句柄,在之后的某个时刻才会触发调用这个函数。
    function(){}()是立即执行这个函数。
    return function(){}就是在这里返回一个functionHandle。
      

  2.   

    有个不解是,既然作用域4的i用的作用域3的i,那么作用域3在执行时,它的i也是需要通过作用域来查找,它找到了作用域1,那么问题就来了,作用域1的i已经是循环累加后的值,那为啥传给作用域3时却不是呢?
      

  3.   


    这就要理解值传递和引用传递了。。
    给个例子var obj = {name: "123"}var fn = function(_obj){
        return function(){
            alert(_obj.name)
        }
    }(obj)obj.name = "222";fn(); //222
    因为对象是引用传递的,再看var obj = 123;
    var fn = function(_obj){
        return function(){
            alert(_obj)
        }
    }(obj)obj = "222";fn(); //123数值是值传递的~el.onclick = function(k){
    return function(){
    alert(k)
    }
    }(i)
    这个就是与第二种情况一样,值传递~
      

  4.   

    是不是这样,匿名函数的使用使它的执行环境中保留了一份当前i值的拷贝,该函数的作用域没有在循环代码结束时被废弃,此时触发元素的click事件,i值的作用域链搜索到作用域3就找到了实际值,而不用搜索到全局执行环境
      

  5.   

    想要相关语言的所有资料吗?java,c++,c#,html,javascript,javaweb,sqlserver,oracle,jquery,Linux,等等等等,程序员必备的学习资料,快来看看吧。
    我的压缩包里面不止一两样东西哦,那可是我学习和工作的所有资料,不管是学习还是工作都会需要。
    http://download.csdn.net/user/yangtonghai