先上代码:
(1)html部分:<dl id="listContainer">
  <dt class="click">标题一</dt>
  <dd class="block">内容一</dd>  <dt>标题二</dt>
  <dd>内容二</dd>  <dt>标题三</dt>
  <dd>内容三</dd>  <dt>标题四</dt>
  <dd>内容四</dd>
</dl>(2)css部分:           *{ margin: 0;
              padding: 0;}           dl{ width: 300px;
               margin: 100px auto;
               border: #666 1px solid;
               border-bottom: none;}
           dt{ line-height: 40px;
               background: #888;
               color: #fff;
               font-size: 14px;
               font-weight: bold;
               padding-left: 20px;
               border-top: #999 1px solid;
               border-bottom: #666 1px solid;
               cursor: pointer;}
           dt.click{ background: #dfdfdf;
                     color: #333;
                     border-bottom: #cfcfcf 1px solid;
                     border-top: #efefef 1px solid;}
           dd{ display:none;
               color: #444;
               font-size: 12px;
               text-align: center;
               padding: 20px;
               background: #efefef;}
           dd.block{ display: block;
                     border-bottom:#666 1px solid;
                     }(3)脚本部分:  /*分别获取dt,dd标签组*/
  var listContainer=document.getElementById('listContainer'),
      dts=document.getElementsByTagName('dt'),
      dds=document.getElementsByTagName('dd');  /*(在给点击的dt改变类名,相邻的dd改变类名之前)判断dt.click,dd.block是否存在并设置类名为空*/
  function disappear(){
    for(var n=0;n<dts.length;n++){
      if(dts[n].className=='click'){
        dts[n].className='';
      }
      if(dds[n].className=='block'){
        dds[n].className='';
      }
    }
  }  /*主要函数---用于隐藏旧选项卡显示新选项卡*/
  function clickEffects(){
    for(var i=0;i<dts.length;i++){
      (function(){
        dts[i].onclick=function(){
          disappear();
          dt[i].className= (this.className!=='click')? 'click':'';
          dds[i].className= (this.className!=='block')? 'block':'';
        }
      })();
    }
  }
window.onload=clickEffects;
函数加载后执行失败。
测试后,该段代码的问题出在clickEffects函数中的匿名函数自执行部分,即:      (function(){
        dts[i].onclick=function(){
          disappear();
          dt[i].className= (this.className!=='click')? 'click':'';
          dds[i].className= (this.className!=='block')? 'block':'';
        }
      })();之后,我将匿名函数引入参数,由i来递值,如下:      (function(num){
        dts[num].onclick=function(){
          disappear();
          this.className= (this.className!=='click')? 'click':'';
          dds[num].className= (this.className!=='block')? 'block':'';
        }
      })(i);函数成功执行。分析之后,发现在最初的未引用参数的匿名函数中:
匿名函数的i值为当前i值;
而匿名函数内部的匿名函数,即click绑定的函数中,i值为4(即i作为clickEffects局部变量在for循环之后的最终值).所以针对每次的click实际上是:
dt[0].onclick=function(){dts[4].className=......;dds[4].className=.....};
dt[1].onclick=function(){dts[4].className=......;dds[4].className=.....};
dt[2].onclick=function(){dts[4].className=......;dds[4].className=.....};
dt[3].onclick=function(){dts[4].className=......;dds[4].className=.....};
因为dts[4]和dds[4]是不存在的,所以函数最终执行失败。而我的疑虑也正在于此:
其实,click绑定的函数中,i=4这个很好理解,作为闭包取clickEffects活动对象的最终值。但是,为什么在其外部的匿名函数中,i的值不总等于4而是取了i的当前值0,1,2,3?这个外部的匿名函数该怎么对待,难道不是clickEffects的闭包?

解决方案 »

  1.   

    function clickEffects(){
        for(var i=0;i<dts.length;i++){
          (function(num){
            dts[i].onclick=function(){
              disappear();
              dt[i].className= (this.className!=='click')? 'click':'';
              dds[i].className= (this.className!=='block')? 'block':'';
            }
          })(i);
        }
      }
    window.onload=clickEffects;
    我来解释下,给添加的外层匿名函数的i是实参,是for循环中的i,当for循环中的i=0,这个i就作为实参传给num这个形参并立即执行,num是一个局部变量,之所以没有消失是因为 dts[i].onclick=function(){
              disappear();
              dt[i].className= (this.className!=='click')? 'click':'';
              dds[i].className= (this.className!=='block')? 'block':'';
            }函数引用了外层函数的变量i,当循环多次就产生多个内部函数,每个内部函数都分别引用外部相应的i
      

  2.   

    因为for里面的匿名函数并没有形成闭包,匿名函数跟onclick定义的函数的区别就在于i什么时候会被用到。
    你把函数改成这样就好理解一些
    function clickEffects(){
        for(var i=0;i<dts.length;i++){
          (function(){
    alert(i);
           }
          })();
        }
      }
    如上面的代码,每次循环执行的时候,匿名函数就会被调用,i就被使用了,当clickEffects执行结束,i就会被回收。
    而不是像定义onclick那样,在定义完成之后并没有用到i,当用户真正去click的时候,才会用到i,这时候才形成了必包,i会一直存在内存里