-2
function addLinks () {
   for (var i=0, link; i<5; i++) {
         link = document.createElement("a");
         link.innerHTML = "Link " + i;
         link.onclick = function (num) {
             return function () {
                 alert(num);
             };
         }(i);
}}

为每个链接创建一个闭包;每个闭包都引用了它创建的范围。由于num每个循环都更新了参数,因此click在第一个链接上它应该 alert 4。不是吗?

4

2 回答 2

2

一点也不,每个函数调用都会获得一个新的num变量副本,因此第一个链接应该警告 0。

如果你真的想让所有的回调共享同一个变量......然后让他们共享同一个变量(包装“num”的东西正是为了避免这个问题,让回调是独立的):

//now all the inner closures use the same "i" variable
//since the variable gets mutated by the for loop
//all links are going to print "5" after the loop ends.
for (var i=0, link; i<5; i++) {
     link = document.createElement("a");
     link.innerHTML = "Link " + i;
     link.onclick = function () {
         alert(i);
     };
}

顺便说一句,这只是因为与其他语言不同,JS 没有循环索引的块范围。for 循环的行为就像你已经完成了

var i;
while(i < 5){
   //...
   i++
}
于 2013-04-07T16:04:16.473 回答
1

不。

而且因为您混淆了几件事:

  1. 函数参数是函数的本地参数(带有一个大的“除非”,为数字 2 保存)
    它们旨在将对象(包括数组/函数)或值别名到函数的范围,无论您选择什么名称。
    目标是允许您将参数重命名为您想要的任何内容,以使内部代码有意义,无论您从外部代码作为参数传入什么。
    这与范围无关。

  2. JS 中的变量如果是对象则通过引用传递,如果是标量则通过值传递。
    传递i到新闭包的全部意义在于将 的值作为i参数传递,而不是对 的引用i如果包含闭包,就会发生这种情况。

如果你要传递一个对象,而该对象就是i上面有 (.obj.i += 1i

对象通过引用传递,标量通过传递。
即使在技术上存在字符串和数字对象,只要您不直接对它们进行任何面向对象的操作,它们就会被转换为标量值。

var i = 3,
    say_i = function () { console.log(i); };

相对

var i = 3,
    say_i = (function (val) { return function () { console.log(val); }(i));

第一个给出了参考i
运行时say_i,它会i实时查看 的值,并将其输出到控制台中。

第二个将一个传递给返回函数的外部作用域,别名为 name val
因为数字是通过值而不是通过引用传递的,所以val总是等于同一件事,除非从内部更改。

如果你在循环之外创建一个函数,你也可以达到同样的结果:

var add_log = function (el, val) { el.onclick = function () { console.log(val); }; },
    i = 0,
    el;

for (; i < ........) {
    el = ....
    add_log(el, i);
}

i是按值传递的,因此所有元素val在其范围表中都有不同的值,因此,每个元素都会记录不同的数字。

于 2013-04-07T16:14:16.173 回答