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
。不是吗?
答案 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)
没有
因为你混淆了几件事:
函数参数是函数的局部函数(带有大的“除非”,保存为数字2)
它们旨在以您选择的任何名称将对象(包括数组/函数)或值替换为函数的作用域。
目标是允许您将参数重命名为您想要的任何内容,以使内部代码有意义,无论您从外部代码传递的参数是什么。
这与范围无关。
JS中的变量通过引用传递(如果它们是对象),如果它们是标量则按值传递。
将i
传递给新闭包的重点是i
的 值 作为参数传递,而不是 引用 到i
,如果 不 包含关闭,会发生这种情况。
如果您要传递一个对象,并且该对象是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
,因此,每个元素都会记录不同的数字。