内部循环中存在JavaScript变量 - 无法访问

时间:2016-08-11 15:21:52

标签: javascript html closures

我正在进行AJAX调用以检索某个州的所有商店。问题是,最后两行是否无法访问我在get调用的return函数中构建的任何变量内容。

    var states = ['TX', 'AZ];

    for(j = 0; j < states.length; j++) {
        var fullHTML = '';
        var full2;
        $.get("//127.0.0.1:8000/api/state-stores/", {state: states[j]}, function(data) {
            console.log(data.stores.length);

            for(var i = 0; i < data.stores.length; i++) {
                store_html = '<tr><td>' + data.stores[i].name + '</td><td>'
                fullHTML += store_html;
            }
        })
        // PROBLEM HERE
        console.log(fullHTML); //empty
        $("#" + states[j].toLowerCase() + "-table").html(fullHTML); //does nothing
    }

我该怎么做才能解决这个问题?我一直在尝试奇怪的全局变量技巧和各种各样的黑客行为,但没有任何工作。

更新 我还尝试将最后两行放在 $.get调用中,但states[j]由于某种原因在循环内无法访问。 调试之后,看起来外部循环中的j在返回函数中是不可访问的。有办法解决这个问题吗?

更新2

我按照答案中给出的建议,fullHTML获取正确连接的字符串,每个fullHTML字符串正在替换只有表格中的最后状态。好像TX标签是唯一接收所有更新的标签。我认为这是基于闭包的,但我不知道如何解决这个问题。

$(function() {
    var states = ['AZ', 'CA', 'CO', 'GA', 'NV', 'NC', 'SC', 'TX'];
    // var states = ['CA'];
    for(var j = 0; j < states.length; j++) {
        var current = j;
        $.get("//127.0.0.1:8000/api/state-stores/", {state: states[j]}, function(data) {
            var fullHTML = '';
            for(var i = 0; i < data.stores.length; i++) {
                store_html = '<tr><td>' + data.stores[i].name + '</td><td>' + data.stores[i].address + '<span class="small-table"><br>' + data.stores[i].city + '</span></td><td>' + data.stores[i].city + '</td><td>' + data.stores[i].state + '</td><td>' + data.stores[i].postal_code + '</td></tr>'
                fullHTML += store_html;
            }
            $('#' + states[current].toLowerCase() + '-table').html(fullHTML);
        })  
    }

});

1 个答案:

答案 0 :(得分:2)

这是异步 $ .get函数。也就是说,代码执行将在该行等待,直到$ .get完成,执行回调函数,然后继续到$ .get之后的下一行。实际上,它将对$ .get函数执行异步调用,并立即继续执行console.log(fullHTML)行。此时无法保证$ .get函数已完成甚至启动,因为它是异步执行的。

至于您对j的可访问性的问题,这是一个回到闭包的问题。当您在$ .get回调中访问时,j变量将引用已经循环的j变量,并且将返回不正确的j值,因为您可能需要从$ .get请求执行时j的值。因此,您希望将j存储在本地闭包中,方法是将其明确声明为var current = j,而不是在$ .get回调中引用j,您可以参考current,它会按预期执行。 这不起作用!

修改

如果我们声明一个匿名函数并在该上下文中执行$ .get,我们可以强制创建一个新的作用域。这不是一个漂亮的解决方案,但它确实有效!

要修复代码,请将调用放在$ .get回调中,如下所示:

var states = ['TX', 'AZ'];

for(j = 0; j < states.length; j++) {
    var fullHTML = '';
    var full2;
    (function() {
        var current = j;
        $.get("//127.0.0.1:8000/api/state-stores/", {state: states[j]}, function(data) {
            console.log(data.stores.length);

            for(var i = 0; i < data.stores.length; i++) {
                store_html = '<tr><td>' + data.stores[i].name + '</td><td>'
                fullHTML += store_html;
            }
            console.log(fullHTML); // not empty anymore
            $("#" + states[current].toLowerCase() + "-table").html(fullHTML); //does stuff
        });
   })();
}

现在,您的代码只会在填充fullHTML变量之前执行已损坏的行。