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

后端 未结 3 1579
再見小時候
再見小時候 2021-01-21 03:43

I have trouble understanding the scoping rules in Javascript.

In the example below, I would assume that scope url variable is private in the for-loop. And that the onloa

相关标签:
3条回答
  • 2021-01-21 04:32

    Javascript is not block-scoped, and thus requires a new function every time you want a new scope. See the answer by 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.

    var imageArray = urlArray.map(function(url) {
        var image = new Image();
        image.src = url;
        image.onload = function() {
            alert(url);
        };
    
        return image;
    });
    
    0 讨论(0)
  • 2021-01-21 04:32

    JavaScript does not have block-scope.

    The only way to create new variable scope is in a 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.


    EDIT:

    Ultimately, you'd never do this if all you need is access to the url.

    You'd just get it from the property of the element via 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.

    0 讨论(0)
  • 2021-01-21 04:32

    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;
    }
    
    0 讨论(0)
提交回复
热议问题