Javascript臭名昭著的循环问题?

Javascript臭名昭著的循环问题?,javascript,closures,Javascript,Closures,我有以下代码片段 function addLinks () { for (var i=0, link; i<5; i++) { link = document.createElement("a"); link.innerHTML = "Link " + i; link.onclick = function () { alert(i); }; document.body.appen

我有以下代码片段

function addLinks () {
    for (var i=0, link; i<5; i++) {
        link = document.createElement("a");
        link.innerHTML = "Link " + i;
        link.onclick = function () {
            alert(i);
        };
        document.body.appendChild(link);
    }
}
函数addLinks(){

对于第一个示例中的(var i=0,link;i),只需将此函数绑定到onclick事件:

function() {alert(i);};
这意味着在单击事件上,js应该提醒addlink函数i变量的值。由于for循环()的原因,它的值将为5

在第二个示例中,生成一个要与另一个函数绑定的函数:

function (num) {
  return function () { alert(num); };
}
这意味着:如果使用值调用,则返回一个将提醒输入值的函数。例如,调用
function(3)
将返回
function(){alert(3)};

在每次迭代中使用值i调用此函数,因此为每个链接创建单独的onclick函数


要点是,在第一个示例中,您的函数包含一个变量引用,而在第二个示例中,在外部函数的帮助下,您将引用替换为实际值。这被称为闭包,大致上是因为您将函数中变量的当前值,而不是保留对它的引用。

在第一个示例中,您只需将此函数绑定到onclick事件:

function() {alert(i);};
这意味着在单击事件上,js应该提醒addlink函数i变量的值。由于for循环()的原因,它的值将为5

在第二个示例中,生成一个要与另一个函数绑定的函数:

function (num) {
  return function () { alert(num); };
}
这意味着:如果使用值调用,则返回一个将提醒输入值的函数。例如,调用
function(3)
将返回
function(){alert(3)};

在每次迭代中使用值i调用此函数,因此为每个链接创建单独的onclick函数

要点是,在第一个示例中,您的函数包含一个变量引用,而在第二个示例中,在外部函数的帮助下,您将引用替换为实际值。这被称为闭包,大致上是因为您将函数中变量的当前值,而不是保留对它的引用。

有关第一个示例的说明:

JavaScript的作用域是函数级的,而不是块级的,创建闭包只意味着将封闭作用域添加到封闭函数的词法环境中

循环终止后,函数级变量i的值为5,这是内部函数“看到”的值

在第二个示例中,对于每个迭代步骤,外部函数文字将计算为一个新的函数对象,该函数对象具有自己的作用域和局部变量
num
,其值设置为当前值
i
。由于
num
从未被修改,它将在闭包的生命周期内保持不变:下一个迭代步骤不会覆盖旧值,因为函数对象是独立的


请记住,这种方法效率很低,因为必须为每个链接创建两个新函数对象。这是不必要的,因为如果使用DOM节点存储信息,它们很容易共享:

function linkListener() {
    alert(this.i);
}

function addLinks () {
    for(var i = 0; i < 5; ++i) {
        var link = document.createElement('a');
        link.appendChild(document.createTextNode('Link ' + i));
        link.i = i;
        link.onclick = linkListener;
        document.body.appendChild(link);
    }
}
函数linkListener(){
警惕(本条第一款);
}
函数addLinks(){
对于(变量i=0;i<5;++i){
var link=document.createElement('a');
appendChild(document.createTextNode('link'+i));
link.i=i;
link.onclick=linkListener;
document.body.appendChild(链接);
}
}
有关第一个示例的说明:

JavaScript的作用域是函数级的,而不是块级的,创建闭包只意味着将封闭作用域添加到封闭函数的词法环境中

循环终止后,函数级变量i的值为5,这是内部函数“看到”的值

在第二个示例中,对于每个迭代步骤,外部函数文字将计算为一个新的函数对象,该函数对象具有自己的作用域和局部变量
num
,其值设置为当前值
i
。由于
num
从未被修改,它将在闭包的生命周期内保持不变:下一个迭代步骤不会覆盖旧值,因为函数对象是独立的


请记住,这种方法效率很低,因为必须为每个链接创建两个新函数对象。这是不必要的,因为如果使用DOM节点存储信息,它们很容易共享:

function linkListener() {
    alert(this.i);
}

function addLinks () {
    for(var i = 0; i < 5; ++i) {
        var link = document.createElement('a');
        link.appendChild(document.createTextNode('Link ' + i));
        link.i = i;
        link.onclick = linkListener;
        document.body.appendChild(link);
    }
}
函数linkListener(){
警惕(本条第一款);
}
函数addLinks(){
对于(变量i=0;i<5;++i){
var link=document.createElement('a');
appendChild(document.createTextNode('link'+i));
link.i=i;
link.onclick=linkListener;
document.body.appendChild(链接);
}
}

基本上,在第一个示例中,您将
onclick
处理程序内的
i
直接绑定到
onclick
处理程序外的
i
上。因此,当
onclick
处理程序外的
i
改变时,
onclick
处理程序内的
i
也会改变


在第二个示例中,不是将其绑定到
onclick
处理程序中的
num
,而是将其传递到一个函数中,然后该函数将其绑定到
onclick
处理程序中的
num
。当您将其传递到函数中时,
i
的值被复制,而不是绑定到
num
。因此当
i更改,
num
保持不变。之所以发生复制,是因为JavaScript中的函数是“闭包”,这意味着一旦有东西传递到函数中,它就“关闭”对于外部修改。

基本上,在第一个示例中,您将
onclick
处理程序内部的
i
直接绑定到
onclick
处理程序外部的
i
上。因此,当
onclick
处理程序外部的
i
发生变化时,
onclick
处理程序内部的
i
将发生变化C
for (var i=1; i<=5; i++) {
    $("#div" + i).click (
        // TODO: Write function to handle click event
    )
}
for (var i=1; i<=5; i++) {
    $("#div" + i).click (
        function(num) {
            // A functions variable values are set WHEN THE FUNCTION IS CALLED!
            // PLEASE UNDERSTAND THIS AND YOU ARE HOME AND DRY (took me 2 years)!
            // Now the click event is expecting a function as a handler so return it
            return function() { alert (num) }
        }(i) // We call the function here, passing in i
    )
}
for (var i=1; i<=5; i++) {

    function clickHandler(num) {    
        $("#div" + i).click (
            function() { alert (num) }
        )
    }
    clickHandler(i);

}