简体   繁体   English

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

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

I have trouble understanding the scoping rules in Javascript.我无法理解 Javascript 中的范围规则。

In the example below, I would assume that scope url variable is private in the for-loop.在下面的示例中,我假设 scope url 变量在 for 循环中是私有的。 And that the onload-event function would see this private instance.并且 onload-event function 会看到这个私有实例。

But things does not seems work like that - the alert will popup with the last url twice.但事情似乎并非如此 - 警报将与最后一个 url 一起弹出两次。

If somebody can clarify what is going on, I'll be grateful.如果有人能澄清发生了什么,我将不胜感激。

<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 does not have block-scope. JavaScript没有块范围。

The only way to create new variable scope is in a function.创建新变量 scope 的唯一方法是在 function 中。

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]);
}

Passing the testArray[i] to a function that creates and returns the new image ensure that the url referenced in the onload handler will be the one that was scoped in the function.testArray[i]传递给创建并返回新图像的 function 以确保在onload处理程序中引用的url将是 ZC1C425268E68385D1AB5074C 中的范围。


EDIT:编辑:

Ultimately, you'd never do this if all you need is access to the url .最终,如果您只需要访问url ,您将永远不会这样做。

You'd just get it from the property of the element via this .您只需通过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 way you're not creating an identical handler function instance in the loop, but rather sharing the same instance, and referencing the element that received the event via this .这样,您就不会在循环中创建相同的处理程序 function 实例,而是共享相同的实例,并引用通过this接收事件的元素。

Javascript is not block-scoped, and thus requires a new function every time you want a new scope. Javascript 不是块范围的,因此每次您想要一个新的 scope 时都需要一个新的 function。 See the answer by patrick dw.请参阅 patrick dw 的答案。

This is why it is advantageous to use [].map(function(x){...}) or [].forEach(function(x){...}) which are in the javascript standard, since you'll need to define those functions anyway.这就是为什么使用 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;
});

Try this:)尝试这个:)

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;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM