关于 Js 循环添加事件时闭包的影响

很高兴有一个纯JS的问题。
1,@杨咖啡 说的JS传参是传值不传址,其实不是这样的。JS中传参有两种方式:by value and   by sharing.
       像C,C++,Java,他们传参方式是by value 和 by reference。前者就是传值,后者是传址。而JS也是这样的,前者是传值,后者是传址。
      By value是对于原始数据类型,例如int,char之类的;而By sharing 和By reference是对于高级数据结构,如Object,struct之类。我们可以想象到一个Object或是struct 不能仅仅通过传值进行传参。
       一个简单的例子说明by reference和 by sharing的不同。
       var bar;
       var foo = bar;
       bar = {'key' : 'value'};
       console.log(foo , bar );
       By sharing 中foo 是undefined , bar 是{'key' : 'value'}; 而By reference 则应该两者都是{'key' : 'value'}。

2.  其实LZ要理解这个问题,要明白JS中的作用域(scope)。
     每个函数在创建完成时,他有3个重要的内置属性(property)也同时被创建。
    {
        AO //记录function内的变量,参数等信息
        this // 就是在调用this.xx的时候的this
        scope // 指向外层函数AO的一个链(在实现的时候,可能通过数组来实现).
    }
    JS中,大家经常讲的Scope其实是这样:SCOPE=AO+scope.
    回到闭包的问题上:
   如果我们这样写这个程序:
    for(var i =0; i<link.length; i++){ //window scope
           link[i].onclick = function(){ alert(i); };  // inner function 

    }
    可以得到inner function的SCOPE是这样的:

     {
          AO 
          this // 等于link[i]
          scope // 指向window的记录,包括我们需要的变量i
     }
     这个for循环会立即执行完毕,那么当onclick触发时,inner function查找变量  i  时,会在AO+scope中找,AO中没有,scope中的变量i已经成为了link.length.

    利用大家所说的闭包写这个程序:
     //here is the window scope
for(var i =0; i<link.length; i++){  

     link[i].onclick = (function(i){  // outer function 
              return function(){  //inner function 
                    alert(i);
               };
     })(i);

}
      分析inner function的SCOPE:
      {
             AO     // no important infomation 
             this   // we don't care it.
             scope  //outer function and window scope
      }
      outer function的SCOPE
      {
            AO  // 包含参数i
            this  // don't care it .
            scope // window scope.
      }     


      这时,如果inner function被触发,他会从自己的AO以及scope(outer function的AO 和 window scope)中找寻变量i.  可以看到outer function的AO中已经包含了i,而且对于这个for循环,会有对应有N个(function(){})() 被创建执行。所以每个inner function都有一个特定的包含了变量 i 的outer function。

      这样就可以顺利输出0,1,2,3。。。。。。。。。

      结论: 我们可以看到,闭包其实就是因为Scope产生的,所以,广义上来讲,所有函数都是闭包。


     另外,这里面也包含了,this, function expression 和function  declaration的区别,这里就不一一讲了。

3. 另外一种方法:
    利用 dom onclick事件的bubble特性,也就是@xiiiiiin所讲的弄个代理。

    在link dom节点的父节点上定义onclick事件监听。参数为e(其他的名字也可以,但要有参数)。 这样我们通过e.target就可以知道是那个子节点被click了,也可以做相应的处理。
     这是一个比较好的方法。(闭包有时会产生内存泄漏)。

大概就说这么多吧,还要上班呢。希望对LZ有用。如果哪里错了,也请多多批评指正。

posted @ 2012-12-04 21:23  坏混混  阅读(196)  评论(0)    收藏  举报