JavaScript 回调函数中的变量总是在循环中获得最后一个值?

IT技术 javascript addeventlistener
2021-03-15 21:08:16

我正在尝试执行以下操作:

我有一组图像并选择(下拉)HTML 元素,每个元素 30 个。我试图在从 1 到 30 的循环中使用 AddEventListener 以便当我更改选择的值时,图像 src 会更新(并且图像会更改)。

AddEventListener 函数是这样的:

function AddEventListener(element, eventType, handler, capture)
{
    if (element.addEventListener)
        element.addEventListener(eventType, handler, capture);
    else if (element.attachEvent)
        element.attachEvent("on" + eventType, handler);
}

我试过了,它奏效了:

var urlfolderanimalimages = "http://localhost/animalimages/";
var testselect = "sel15";
var testimg = "i15";

AddEventListener(document.getElementById(testselect), "change", function(e) {
    document.getElementById(testimg).src = urlfolderanimalimages + document.getElementById(testselect).value;
    document.getElementById(testimg).style.display = 'inline';

    if (e.preventDefault) e.preventDefault();
    else e.returnResult = false;
    if (e.stopPropagation) e.stopPropagation();
    else e.cancelBubble = true;
}, false);

但是后来我尝试在循环中调用它,但它不起作用。添加了事件,但是当我更改任何选择时,它将更新最后一个(ID 为 i30 的图像)。

var urlfolderanimalimages = "http://localhost/animalimages/";

for (k=1;k<=30;k++) {
    var idselect = "sel" + k;
    var idimage = "i" + k;

    AddEventListener(document.getElementById(idselect), "change", function(e) {
        document.getElementById(idimage).src = urlfolderanimalimages + document.getElementById(idselect).value;
        document.getElementById(idimage).style.display = 'inline';

        if (e.preventDefault) e.preventDefault();
        else e.returnResult = false;
        if (e.stopPropagation) e.stopPropagation();
        else e.cancelBubble = true;
    }, false);

}

我究竟做错了什么?我是 JavaScript 的新手(以及一般的编程),很抱歉引起呕吐的代码 :(

2个回答

问题是您正在“关闭”同一个变量

var 不声明变量1它只是在给定的执行上下文中为标识符注释“停止查找”。

请参阅Javascript Closures "FAQ Notes"了解所有详细信息。关于“执行上下文”和“作用域链”的部分是最有趣的。

常见的习惯用法是执行双重绑定以创建新的执行上下文。

例如

var k
for (k = 1; k < 10; k++) {
  setTimeout((function (_k) {
    return function () {
      alert(_k)
    }
  })(k), k * 100)
}

从 JavaScript 第 5 版开始Function.bind(它也可以在第 3 版中实现,例如从prototype.js 绑定),可以这样使用:

var k
for (k = 1; k < 10; k++) {
  setTimeout((function () {
     alert(this)
  }).bind(k), k * 100)
}

1该构建称为在ECMAScript规范一个变量声明。然而,尽管可能被视为具有误导性,这种陈述强调了一个观点:另见“变量提升”。

非常感谢,pst。老实说,我对此很陌生,所以昨晚我并没有完全掌握它(尽管真的很晚而且我真的很累,所以这可能是其中的原因:p)。我今天再读一遍,看看我能不能让它工作。再次感谢!:)
2021-04-15 21:08:16

我还在http://meshfields.de/event-listeners-for-loop/找到了这个解决方案

var myArr = [0,1,2,3]; 

for (var i = 0; i < myArr.length; i+=1) { 

(function (i) { 

    document.getElementById('myDOMelement' myArr[i]).onclick = function () { 

        if (window.console.firebug !== undefined) { 
            console.log('myDOMelement' myArr[i]); 
        } 
        else { 
                alert('myDOMelement' myArr[i]); 
        } 
        }; 
    }) (i); 
}