这段错误的代码,书里说问题在于,“事件处理器函数(我理解是function(e))绑定了变量i,而不是函数在构造时的变量i的值”,此句话,我完全没看明白,在我眼里,i只有一个...真说多余的话,(e)里面的e是多余的到是真的,还有就是函数结尾少了个()去自执行,求高人讲解一下,谢谢。var add_the_handlers = function (nodes){
var i;
for (i= 0; i < nodes.length; i +=1){
nodes[i].onclick = function (e) {
alert(i);
}
}
};

解决方案 »

  1.   

    var add_the_handlers = function (nodes){
        var i;
        for (i= 0; i < nodes.length; i +=1){
            nodes[i].onclick = function (e) {
                alert(i);
            }
        }
    };
    正常情况下只会弹出nodes.length,事实上用不同浏览器弹出的会不同,以前测试的,忘记了是啥了,总之都是在nodes.length跟nodes.length之间。
    其实上面的方法弹出来的是变量i,而i变量在for执行完的时候已经是nodes.length(当然浏览器内部的for执行不同造成了我上面说的偏差。)
    可以选择闭包方式解决。
    var add_the_handlers = function (nodes){
        var i;
        for (i= 0; i < nodes.length; i +=1){
            nodes[i].onclick = (function (n) {
                return function(e){
                    alert(n);
                }
            })(i)
        }
    };
    这个时候就造成了一个闭包,click绑定的事件句柄在执行的时候,他的执行环境就是那个只执行一次的匿名函数,而这个匿名函数的环境中有个变量n是分别是每次for循环执行的时候赋值的。
    - -# 语言表达有问题,貌似我自己都没听懂。
    不知道楼主能理解不?
      

  2.   

    我分开解释下吧。<div id="a">00000</div>
    <script>
    var aa = (function(n){
    return function(){
    alert(n);
    }
    })(456464564);
    document.getElementById('a').onclick = aa;
    </script>javascript函数 执行的时候会有一个执行环境,函数可以访问该环境下,父函数(父对象?不知道该咋称呼)的变量。
    就是儿子可以访问他爹的变量,但是他爹没法用他儿子的媳妇儿(私有变量)。
    正如上例,n只是那个闭包函数内部的变量,但是抛出了一个function,他是匿名函数内部的(就是儿子),他能弹出他爹的变量。
    所以就导致在别的地方,只要用了他儿子,就能知道他爹的一切。
      

  3.   

    我好像有点明白这个道理了,是不是说,在循环的时候,每个node的onclick被赋予了变量i(类似于var i;但没有var i=几;我这么理解不知道对不对?),此时还没有确定最后变量i的值,等到循环结束,变量i的值即为length,所以当onclick真的被点击的时候,里面的i会被赋值为length?
      

  4.   

    for中,我们为每个匿名函数都传进去了一个参数i,每个“爹”获得的变量i都不同,但是我们可以通过他爹扔出去(return)的儿子(就是抛出的function)来得到传进去的那个i;
    更多的闭包的知识,楼主还是看下相关文档吧。
      

  5.   

    不就是普通的菜单嘛 就是换了个图而已
    好吧,你说里面子菜单是ajax请求的。但是现在的菜单都一样的
      

  6.   

    Crazywa,我正在仔细消化你的讲解,稍等一下,我看能不能吃透这个道理;
    我现在正是刚接触闭包理论,有一些看不明白,所以上来问。
      

  7.   


    var g = (function(aa){
       return aa;
    })(15646)这个时候,g获得的是aa的值,也就是15646;var g = (function(aa){
       return function(){}
    })(15646)这个时候,g获得的是一个function,只不过里面什么也没有var g = (function(aa){
       return function(){
           alert(aa)
       }
    })(15646)这个时候g获得的是一个function,并且他能弹出父亲的aa来,并且,父亲已经执行了,也就是说父亲内部已经定下来了,他的aa就是传进去的15646
    而当吧这个放到for里面的时候,function (){}就代表定义一个新函数,所以,每一次for的时候父亲是通过function(){}重新定义的匿名函数,而且父亲都会当场执行,执行的结果是把当时的i的值作为自己的东西保存起来,并且把儿子扔出去(return)。
    而儿子被赋给了
    xx.onclick
    所以在被点击的时候,儿子出卖了当时父亲保存的值。
      

  8.   

    那就下面的code而言,每个传进去的变量i,又是如何被内部函数使用的?我能理解内部函数是可以使用变量i的,只是不明白哪行代码使用了?我感觉现在是我对return这个部分的理解有问题,下面的内部函数并没有用到i啊?但不管你,还是书上,都是这么用的,肯定是我对这个地方的理解不对,请指教一下,谢谢
      return function(e){
      alert(n);
      }
      

  9.   

    for{ //写法错误 无视
      (function(z){ })(i)//请注意这里,后面的括号代表运行前面的函数,括号里是传进去的值.z是形参、i是实参。
    }
      

  10.   

    那就这下面而言,i传进了外部函数function(n),这个我完全能理解,没问题,但是如果下面不是alert(e),而是alert(e)的话,(书上的代码如此),我不太理解i的值又是如何传到alert(e)上的?  nodes[i].onclick = (function (n) {
      return function(e){
      alert(n);
      }
      })(i)
      

  11.   

    e应该是event对象。
    在事件处理函数里,标准浏览器会将事件对象event作为第一个参数传进去(ie除外,BS微软)。
    我们将这个function赋给onclick了,它的第一个参数就应该是event,
      

  12.   

    而i没有传给return 那个函数。
    i只是他爹的参数。
    参数可以看做是函数的私有变量。
    也就是i是他爹的私有变量,他只是拿他爹的i。
    儿子拿老子的,天经地义。
      

  13.   


      nodes[i].onclick = (function (n) {
          function fn(e){
            alert(n);
          }
          return fn;
      })(i)这样写明白吗?
    e跟i没关系,只是儿子函数fn的参数。
    而弹出去的n是他爹的私有变量,这个私有变量就是他爹执行的时候获得的i。
      

  14.   

    嗯,能理解,但如果alert(e)呢?改成这样,这样子的话和书上的一样,我主要是不明白下面这种情况
     nodes[i].onclick = (function (n) {
          function fn(e){
            alert(e);
          }
          return fn;
      })(i)
      

  15.   

    这个传入的i根本在函数内部都没用到,最终就是给每个节点的事件添加了一个函数:
    fn(e){alert(e)}
      

  16.   

    var add_the_handlers = function (nodes){
        var i;
        for (i= 0; i < nodes.length; i +=1){
            nodes[i].onclick = function (e) {
                alert(i);
            }
        }
    };
    这段代码其实是没有问题的,定义了一个增加事件响应函数而已,参数是节点数组,这样调用:
    add_the_handlers([node1,ndoe2]);
    这样就会给传入的2个节点增加一个事件响应函数,书里的原话都没错,是LZ理解错了!
    之所以最终返回的i值都是nodes.length,这个涉及到了闭包的概念了,子函数引用到了父函数的变量i,因此在父函数作用结束后,其中的i变量不会被删除,依然存在于内存中,而每个node的事件函数引用的i都是指向同一个内存区域的,所以最终的值都会一样!
      

  17.   


    那比如说把alert(e)改成alert(n)的话,那是不是这个就对了?我现在怀疑是不是书上印错了...
      nodes[i].onclick = (function (n) {
      function fn(e){
      alert(n);
      }
      return fn;
      })(i)
      

  18.   


    改成alert(n)的话,这个n就是参数i的副本,不是i的引用了,所以能够按照顺序的弹出数字,而不是像alert(i)一样弹出的都是一样的值
      

  19.   


    这是书上的源码,也就是说如果按照书上的源码看,实际上i根本就没有被用到,如果是想在onclick的时候,弹出当前节点的序号的话,应该改成后alert(i),这个i必须与外层函数的形参一样,对吗?
    书上源码:var add_the_handlers = function (nodes) {
    var i;
    for (i = 0; i < nodes.length; i += 1) {
    nodes[i].onclick = function (i) {
    return function (e) {
    alert(e);
    };
    }(i);
    }
    }
    我怀疑书上印错了,实现弹出序号的功能的话,应该是:var add_the_handlers = function (nodes) {
    var i;
    for (i = 0; i < nodes.length; i += 1) {
    nodes[i].onclick = function (i) {
    return function (e) {
    alert(i);//这里的i应该与function (i)的形参一致才能有效?
    };
    }(i);
    }
    }
      

  20.   

    这个书上是对的,此时的e就是你传的i,这个代码可以看作
    nodes[i].onclick = (function (n) {
          function fn(e){
            alert(e);
          }
          return fn;
      })(i)
    注册后nodes[i].onclick = function fn(i){
            alert(i);
          }
    这个i的值是运行环境里的i,
      

  21.   


    哦~那如果书上是对的话,我就是非常不明白这个地方,为什么里面的e就是外面的i了?我一直就困惑在这个地方,比如你说的
      nodes[i].onclick = (function (n) {
      function fn(e){
      alert(e);
      }
      return fn;
      })(i)自执行完后,就等于:
      nodes[i].onclick = function fn(i){
      alert(i);
      }那这是什么原理使得e就是i了?
      

  22.   

    还在这墨迹。
    你把书上的代码敲一下不就知道是否正确了吗?
    你alert(typeof e)
    如果是object就是event对象,如果是Number就是那个i了
      

  23.   


    <div>f</div>
    <div>f</div>
    <div>f</div>
    <div>f</div>
    <div>f</div>
    <script>
    var a = document.getElementsByTagName("div");
    for(var i = 0,j=a.length;i<j;i++){
    a[i].onclick = (function(n){
    return function (e){
    alert(typeof e);
    }
    })(i);
    }
    </script>如果弹出来是undefined(ie下)或者object(ff下)的话,那么e就应该是event。
    也就是说e跟i没有任何联系,只是n被赋予了i的值。但是!惊叹号!
    请看好书上的代码 是否是这样的for(var i = 0,j=a.length;i<j;i++){
        (function(n){
    a[n].onclick = function(e){
                alert(n);
            }
         })(i);
    }这样也正确。
    看代码需要仔细。
    另外,我建议楼主看一下《JavaScript权威指南 第五版》(传说中的“犀牛书”);
    那上面的解释确实不错。
      

  24.   

      js 闭包nodes[i].onclick = (function (n) {
      alert(n);
      })(i);
      

  25.   

    这段代码我可能说错了,这个e应该就是楼上所说的event,因为return fn后click就指向了fn!书里写错了!
      

  26.   

    书中的代码就是这个样子,我测试了一下,FF下alert出来的是[Object MouseEvent],如果改成alert(i)也就是我理解的获取外部函数的形参i的话,功能就对了,这个地方终于明白了...
    但是有个小小的问题,根据书上源码的话,为什么alert出来的会是[Object MouseEvent]?e这个时候是onclick事件本身?
    var add_the_handlers = function (nodes) {
        var i;
        for (i = 0; i < nodes.length; i += 1) {
            nodes[i].onclick = function (i) {
                return function (e) {
                    alert(e);
                };
            }(i);
        }
    }
      

  27.   

    对的,
    var add_the_handlers = function (nodes) {
        var i;
        for (i = 0; i < nodes.length; i += 1) {
            nodes[i].onclick = function (i) {
                return function () {
                    alert(i);
                };
            }(i);
        }
    }
    这样看看结果是什么
      

  28.   

    在上面应该是i吧?
    var add_the_handlers = function (nodes) {
      var i;
      for (i = 0; i < nodes.length; i += 1) {
      nodes[i].onclick = function (i) {
      return function (i) {
      alert(i);
      };
      }(i);
      }
    }
    这样的话是不是又是event啊?
      

  29.   

    javascript中,任何对象都有一个toString方法
    这个方法将返回把对象强制转换成字符串的值。
    但是对于一些对象,无法将其转换成字符串,他们有自己的toString的值。
    Object的就是 [Object Object]
    Array的是 [Object Array]
    你onclick事件会把事件对象event作为第一个参数传进去,所以那个e其实是个event事件
    alert的时候,会把参数自动toString(),你那个event事件的toString就是[Object MouseEvent]
    你也可以
    alert(e.toString());
    应该会得到相同的结果。
      

  30.   


    这个你错了,e就是e,在FF下,是事件对象event,和i扯不到半点关系,i是作为参数传给了最外层的n,此时n保留了当时i的值的副本,e完全和i扯不上关系
      

  31.   


    大哥说笑了,你还能在乎我这点分,不过我发现就是你讲的最明白,最后我肯定会加分的,虽然没太多分可以送...关于这个解释,我大致已经明白了,讲得非常透,可最后还有一个问题,为什么在这个地方会把event当做第一个参数传进去呢?这会在什么情况下发生呢?谢谢谢谢~javascript中,任何对象都有一个toString方法
    这个方法将返回把对象强制转换成字符串的值。
    但是对于一些对象,无法将其转换成字符串,他们有自己的toString的值。
    Object的就是 [Object Object]
    Array的是 [Object Array]
    你onclick事件会把事件对象event作为第一个参数传进去,所以那个e其实是个event事件
    alert的时候,会把参数自动toString(),你那个event事件的toString就是[Object MouseEvent]
    你也可以
    alert(e.toString());
    应该会得到相同的结果。
      

  32.   

    这个又扯远了
    w3c制定的规则,在事件触发的时候,将event对象作为第一个参数传给处理函数。
    标准浏览器都支持这一规范的,比如谷歌、苹果、火狐等等吧。
    只是ie觉得自己很甩牛X,不支持这一规范。
      

  33.   

    http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-flow-capture