变量在Javascript

时间:2015-05-25 11:09:19

标签: javascript

我对以下代码的输出有疑问。

var _list = [{id:0}, {id:1}, {id:2}, {id:3}, {id:4}];

function storeList() {
    for (var i = 0, j = _list.length; i < j; i++) {
        var key = makeKey(_list[i].id);
        _db.setValue(
            function() {
                console.log("OK: store a value of " + key);
            },
            function() {
                throw "ERR: can't store a value of " + key;
            },
            databaseName,
            key,
            _list[i]);
    }
}

storeList();

我希望它应该输出:

OK: store a value of 0
OK: store a value of 1
OK: store a value of 2
OK: store a value of 3
OK: store a value of 4

然而,它输出:

OK: store a value of 4
OK: store a value of 4
OK: store a value of 4
OK: store a value of 4
OK: store a value of 4

为什么呢?什么是正确的输出方式? 我在Android Webview上运行这个javascript代码。

提前致谢。

2 个答案:

答案 0 :(得分:3)

你需要关闭。您可以通过在创建密钥后将代码包装在自执行函数(IIFE

中来完成此操作
(function(key) {
    db.setValue(
        function() {
            console.log("OK: store a value of " + key);
        },
        function() {
            throw "ERR: can't store a value of " + key;
        },
        databaseName,
        key,
        _list[i]
    );
})(key);

这是因为之前key的范围可见所有您的迭代setValue来电。使用IIFE,您传递的密钥范围在&#39;内。每次setValue来电。

答案 1 :(得分:1)

db.setValue是一种异步方法。因此,当您调用它时,它会与主程序流分离,同时保持对循环计数器i的访问。 Javascript总是在执行任何异步代码之前完成当前流程。所以你的循环运行4次,每次创建一个异步代码块,只能在当前正在执行的程序(for循环)完成后运行。

请注意,每个异步块都可以访问相同的i。因此,当他们执行时,他们所看到的只是在主流完成后存在的i的值(在这种情况下是4)。

考虑到这一点,处理这些问题的最简单方法是创建一个闭包。基本上,您将为每个异步块提供i的副本,该副本将保留在创建块时的值(除非您的异步块更改它)。你可以像@AmmarCSE描述的那样通过生活来做到这一点。更简洁的方法是在方法中移出这些东西。

function setValue (i) {
    var key = makeKey(_list[i].id);
    _db.setValue(
        function() {
            console.log("OK: store a value of " + key);
        },
        function() {
            throw "ERR: can't store a value of " + key;
        },
        databaseName,
        key,
        _list[i]
    );
};

function storeList() {
    for (var i = 0, j = _list.length; i < j; i++) {
        setValue(i);
    }
}
相关问题