【问题标题】:Javascript scope issues within an anonymous function [duplicate]匿名函数中的Javascript范围问题[重复]
【发布时间】:2014-04-07 19:06:55
【问题描述】:

当我在谷歌上搜索与发帖人类似的问题时,我发现了一个帖子 (https://bbs.archlinux.org/viewtopic.php?id=58640)。

他试图找出下面代码的修复方法。

for(var i=0; i<3; i++) {
    req[i] = new XMLHttpRequest();
    req[i].onreadystatechange = function() {

        if(req[i].readyState == 4 && req[i].status == 200) {
            URL = url[i];
            success();
        } 

    }
    req[i].open("GET", url[i], true);
    req[i].send(null);    
}

解决办法是

for(var i=0; i<3; i++) {
    req[i] = new XMLHttpRequest();
    req[i].onreadystatechange = function(index) {
              return function() {
                    if(req[index].readyState == 4 && req[index].status == 200) {
                    URL = url[index];
                    success();
                   }
        };
    }(i);
    req[i].open("GET", url[i], true);
    req[i].send(null);    
}

这是因为 req[i] 的范围问题。

我用类似的函数测试了onreadystatechangei 的值,它打印出2、2、2,而不是0、1、2。

显然那里的i 值发生了一些事情,但我不确定发生了什么。

【问题讨论】:

  • 另外,如果有人知道更好的解决方案,请添加。谢谢。
  • 这是新开发者非常常见的问题,但如果你不知道发生了什么,甚至谷歌也几乎不可能。我投票结束了这个问题,因为它是重复的,但那里的链接解释了发生了什么。此外,您可能会发现这也很有帮助:mennovanslooten.nl/blog/post/62
  • 你需要测试index的值,而不是i

标签: javascript


【解决方案1】:

这个问题可以简化为

for(var i=0; i<3; i++) {
    setTimeout(function() {
        console.log(i);
    }, 0)
}

它输出333而不是012

问题在于函数中的i 与循环中使用的i 相同,并且由于在循环的所有迭代之后调用该函数,所以它始终是3

您可以使用 ES6 let 修复它:

for(var i=0; i<3; i++) {
    let j=i;
    setTimeout(function() {
        console.log(j);
    }, 0)
}

之所以有效,是因为let 声明了一个块范围的局部变量。你不能使用var 做同样的事情,因为它的作用域是当前的执行上下文。

或者你可以使用包装函数:

for(var i=0; i<3; i++) {
    (function(j) {
        setTimeout(function() {
            console.log(j);
        }, 0)
    })(i);
}

for(var i=0; i<3; i++) {
    (function() {
        var j = i;
        setTimeout(function() {
            console.log(j);
        }, 0)
    })();
}

但是最好将它移到循环之外,以避免在每次迭代时重新创建它:

function f(j) {
    setTimeout(function() {
        console.log(j);
    }, 0)
}
for(var i=0; i<3; i++) {
    f(i);
}

【讨论】:

    猜你喜欢
    • 2013-06-25
    • 1970-01-01
    • 1970-01-01
    • 2011-02-13
    • 2010-12-19
    • 2012-10-12
    • 1970-01-01
    • 2013-01-11
    • 2013-11-22
    相关资源
    最近更新 更多