Javascript 变量用作函数参数后会发生变化

Javascript 变量用作函数参数后会发生变化,javascript,Javascript,我循环浏览了一些元素,然后添加了新元素,这些元素在单击时应该可以操纵这些元素。很难解释,所以请看一下这把小提琴,让它更清楚: 为了简洁起见,有趣的部分是此代码伪代码: for (var i = 0; i < divs.length; i++) { var div = divs[i]; someOtherElement.addEventListener("click", function () { testDiv(div); // always refers

我循环浏览了一些元素,然后添加了新元素,这些元素在单击时应该可以操纵这些元素。很难解释,所以请看一下这把小提琴,让它更清楚:

为了简洁起见,有趣的部分是此代码伪代码:

for (var i = 0; i < divs.length; i++) {
    var div = divs[i];

    someOtherElement.addEventListener("click", function () {
        testDiv(div); // always refers to the last div because variable is overwritten next loop
    });
}

我希望testDiv调用分别引用div 1、div 2、div 3,但是它们都引用div 3,因为变量在下一个循环迭代中被覆盖。我怎样才能解决这个问题呢?

这是一个经典问题。以下是通常的解决方法:

for (var i = 0; i < divs.length; i++) {
    (function(div){
      someOtherElement.addEventListener("click", function () {
        testDiv(div);
      });
    })(divs[i]);
}
要理解问题和解决方案,您必须知道,在JavaScript中,非全局变量的作用域是声明该变量的函数的调用。这意味着

在代码中,只有一个div变量 在解决方案中,调用中间函数可以生成不同的div变量
这是一个经典问题。以下是通常的解决方法:

for (var i = 0; i < divs.length; i++) {
    (function(div){
      someOtherElement.addEventListener("click", function () {
        testDiv(div);
      });
    })(divs[i]);
}
要理解问题和解决方案,您必须知道,在JavaScript中,非全局变量的作用域是声明该变量的函数的调用。这意味着

在代码中,只有一个div变量 在解决方案中,调用中间函数可以生成不同的div变量
这是解决问题的另一种方法

function testDiv(d) {
    // this doesn't work as expected, it always shows "Div 3"
    alert(d.innerText);
}

var divs = document.getElementsByTagName("div");

for (var i = 0; i < divs.length; i++) {
    var div = divs[i];
    var a = document.createElement("a");
    a.index = i;  
    a.innerText = "[this should point to Div" + (i+1) + "]";
    a.href = "#";
    a.addEventListener("click", function (e) {
        var e = e || window.event;
        var tg = e.target || e.srcElement;
        testDiv(divs[tg.index]);
    });
    document.body.appendChild(a);
}

这是解决问题的另一种方法

function testDiv(d) {
    // this doesn't work as expected, it always shows "Div 3"
    alert(d.innerText);
}

var divs = document.getElementsByTagName("div");

for (var i = 0; i < divs.length; i++) {
    var div = divs[i];
    var a = document.createElement("a");
    a.index = i;  
    a.innerText = "[this should point to Div" + (i+1) + "]";
    a.href = "#";
    a.addEventListener("click", function (e) {
        var e = e || window.event;
        var tg = e.target || e.srcElement;
        testDiv(divs[tg.index]);
    });
    document.body.appendChild(a);
}


请张贴完整的代码。。。someOtherElement是什么?抱歉,这只是伪代码,完整的代码在JSFIDLE中,以便于brevitypls发布完整的代码。。。someOtherElement是什么?抱歉,这只是伪代码,完整的代码在JSFIDLE中,为了方便起见,someOtherElement获得n个应用的单击处理程序-当单击someOtherElement时调用testDiv n次?其中n=div。length@NimChimpsky我希望这是伪代码这一事实也意味着实际上有不同的元素。但是,如果OP真的将event N time绑定到同一个元素上,这一点值得注意,这个元素不是很糟糕,但是可以优化。SomeOther元素是在每个循环中动态创建的,它不是同一个元素。它是一个HTML锚元素,然后添加到页面的其他地方。我正在编写代码,以使用锚点展开和折叠div。我不确定是每次重写clickhandler,还是创建多个不同的处理程序。@如果是同一个元素,则会添加侦听器,将不会删除或重写。因此,someotherElement获得n个应用的单击处理程序-testDiv在单击someotherElement时被调用n次?其中n=div。length@NimChimpsky我希望这是伪代码这一事实也意味着实际上有不同的元素。但是,如果OP真的将event N time绑定到同一个元素上,这一点值得注意,这个元素不是很糟糕,但是可以优化。SomeOther元素是在每个循环中动态创建的,它不是同一个元素。它是一个HTML锚元素,然后添加到页面的其他地方。我正在编写代码,以使用锚来扩展和折叠div。我不确定clickhandler是否每次都被覆盖,或者是否创建了多个不同的处理程序。@如果是同一个元素,则将添加侦听器,不会删除或覆盖。谢谢,它也可以正常工作!这是一个聪明的方法,我不知道。我不理解.index部分,我现在将阅读它。基本上,您可以在运行时向任何对象添加属性。我在利用这种行为:谢谢你,它也很好用!这是一个聪明的方法,我不知道。我不理解.index部分,我现在将阅读它。基本上,您可以在运行时向任何对象添加属性。我正在利用这种行为: