Javascript:在for循环中定义的每个事件处理程序都是相同的,使用上次迭代的值

Javascript: every event-handler defined in for-loop is the same, uses last iteration's values

本文关键字:迭代 程序 循环 for 定义 事件处理 Javascript      更新时间:2023-09-26

我很难理解Javascript中的范围规则。

在下面的示例中,我假设范围 url 变量在 for 循环中是私有的。并且加载事件函数将看到此私有实例。

但事情似乎并非如此 - 警报将两次弹出最后一个 url。

如果有人能澄清发生了什么,我将不胜感激。

<html>
<head>
</head>
<body>
<script type="text/javascript">
    var testArray = ["http://g0.gstatic.com/images/icons/onebox/weather_rain-40.png", "http://g0.gstatic.com/images/icons/onebox/weather_scatteredshowers-40.png"];
    for (var i=0;i<testArray.length;i++){
        var img = new Image();
        var url = testArray[i];
        img.onload = function(){
            alert(url);
        }
        img.src = url;
    }
</script>
</body>
</html>

JavaScript 没有块作用域

创建新变量作用域的唯一方法是在函数中。

var testArray = ["http://g0.gstatic.com/images/icons/onebox/weather_rain-40.png", "http://g0.gstatic.com/images/icons/onebox/weather_scatteredshowers-40.png"];
function createImg( url ) {
    var img = new Image();
    img.onload = function(){
        alert(url);
    }
    img.src = url;
    return img;
}
for (var i=0;i<testArray.length;i++){
    var img = createImg(testArray[i]);
}

testArray[i]传递给创建和返回新图像的函数可确保onload处理程序中引用的url将是函数中作用域

的函数。

编辑:

最终,如果您只需要访问url,您将永远不会这样做。

您只需通过 this 从元素的属性中获取它。

function onloadHandler(){
    alert( this.src );  // <--- get the url from the .src property!
}
var testArray = ["http://g0.gstatic.com/images/icons/onebox/weather_rain-40.png", "http://g0.gstatic.com/images/icons/onebox/weather_scatteredshowers-40.png"];
for (var i=0;i<testArray.length;i++){
    var img = new Image();
    var url = testArray[i];
    img.onload = onloadHandler;
    img.src = url;
}

这样,您就不会在循环中创建相同的处理程序函数实例,而是共享相同的实例,并引用通过 this 接收事件的元素。

Javascript 不是块作用域,因此每次需要新作用域时都需要一个新函数。请参阅帕特里克 dw 的答案。

这就是为什么使用 javascript 标准中的[].map(function(x){...})[].forEach(function(x){...})是有利的,因为无论如何你都需要定义这些函数。

var imageArray = urlArray.map(function(url) {
    var image = new Image();
    image.src = url;
    image.onload = function() {
        alert(url);
    };
    return image;
});

试试这个:)

var testArray = ["http://g0.gstatic.com/images/icons/onebox/weather_rain-40.png", "http://g0.gstatic.com/images/icons/onebox/weather_scatteredshowers-40.png"];
for (var i=0;i<testArray.length;i++){
    var img = new Image();
    var url = testArray[i];
    img.onload = function(){
        alert([img.src, url, i]);
    }
    img.src = url;
}