局部变量和参数之间的区别

时间:2013-04-07 15:54:20

标签: javascript

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上,它应提醒4。不是吗?

2 个答案:

答案 0 :(得分: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);
     };
}
BTW,这只会发生,因为与其他语言不同,JS没有循环索引的块范围。 for循环的行为就像你已经完成了

var i;
while(i < 5){
   //...
   i++
}

答案 1 :(得分:1)

没有

因为你混淆了几件事:

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

  2. JS中的变量通过引用传递(如果它们是对象),如果它们是标量则按值传递。
    i传递给新闭包的重点是i 作为参数传递,而不是 引用 i,如果 包含关闭,会发生这种情况。

  3. 如果您要传递一个对象,并且该对象是i上的obj.i += 1,那么再次关闭或不关闭,每个函数都会指向{的相同值{1}},因为它们都对同一个对象共享相同的引用。

    对象 引用 传递, scalars 值传递 EM> 即可。
    即使有技术字符串和数字对象,只要您不直接使用它们进行任何面向对象的操作,它们就会转换为标量值。

    i

    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
    因为数字是按值传递的,而不是通过引用传递的,所以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,因此,每个元素都会记录不同的数字。