【问题标题】:Can access elements of array, but cannot iterate over可以访问数组的元素,但不能迭代
【发布时间】:2012-10-08 13:46:21
【问题描述】:

我有一个 URL 数组,以及我从外部提取的一组数据。 URL 和数据完美地一一对应。我尝试这样做:

for (var i = 0; i < children.length; i++) {
    urls.push(children[i].data.url); 
}

for (var i = 0; i < children.length; i++) { 
    $.ajax({
         url: DATA_SOURCE,
         dataType: "jsonp",
         success: function (data2) {                           
             console.log(urls[0]);
             console.log(urls[i]);
         }
    });                        
}

第一个日志总是打印urls 数组的第一个元素。我可以将数字更改为任何其他有效索引并且它可以工作。然而,second 日志总是打印 undefined。我最初是从第二个循环中获取 url,但我把它拿出来以防万一它被证明是一个异步错误或什么的。 urls 被初始化为 Array,而不是 Object。将第二个日志从成功函数中取出(并进入 for 循环的主要范围)使其按预期执行。我很乐意将它归结为 ajax 请求以某种方式搞砸了它,但是为什么第一个日志会按预期执行?

有什么想法吗?

【问题讨论】:

  • 为什么不能直接将 children[i].data.url 放入 ajax 而不是使用 urls 作为另一个数组

标签: javascript jquery ajax arrays


【解决方案1】:

$.ajax 是异步的,这意味着当回调(成功)运行时,循环已经运行完毕,现在设置为 children.length

访问 urls[ i ],等于 urls[ children.length 因此未定义。

一个简单的解决方法是为每次迭代创建范围

for (var i = 0; i < children.length; i++) { 
  (function( index ) {
    $.ajax({
       url: DATA_SOURCE,
       dataType: "jsonp",
       success: function (data2) {                           
         console.log(urls[ index ]);
        }
    }); 
  })( i );                       
}

【讨论】:

    【解决方案2】:

    +1 对 Pantelis 的回答,虽然只是有点迂腐的评论:没有真正需要将 整个 ajax 调用包装在 IIFE 中,只有成功回调需要引用 " i 的当前" 值,所以这样就可以了:

    for (var i = 0; i < children.length; i++)
    {
        $.ajax({
           url: DATA_SOURCE,
           dataType: "jsonp",
           success: ((function( index ) 
           {
               return function (data2)
               {
                   console.log(urls[ index ]);
               };
           })(i)
        });
    }
    

    【讨论】:

    • 这与我发布的内容有何不同?
    • @Asad:不是,但是当我开始输入此内容时,您的答案尚未更新。我刚刚发布了这个以添加到 Pantelis 的答案......唯一的区别是您声称 i 将是未定义的,而实际上,它不是
    • 酷,真的很棒!我选择包装整个 ajax 调用的唯一原因是,在其余的回调(错误、进度)中也可能需要 i。但我更喜欢你在这种情况下的解决方案。
    【解决方案3】:

    这是因为最终调用成功函数时 i 未定义。您需要将 i 的当前值传递给您正在生成的成功函数。

    for (var i = 0; i < children.length; i++) { 
        $.ajax({
             url: DATA_SOURCE,
             dataType: "jsonp",
             success: (function (count) {
                 return(function(data2){console.log(urls[0]); console.log(urls[count]);});        
             })(i)
        });                        
    }
    

    在这里,为每次迭代生成的成功函数略有不同,因为它记录了不同的值。

    【讨论】:

    • i 不是未定义的,当成功函数最终被调用时,它将等于children.length。因为成功回调引用了i,所以不会超出范围,但是值会一次又一次递增
    • 成功函数是在全局上下文中调用的,不是吗?并且由于他(正确地)使用var i = 0,因此我将无法在成功处理程序的上下文中访问。除非这些循环本身在全局上下文中运行,在这种情况下你是对的。
    • 不,这不是调用成功函数的上下文的问题:它被声明为对象字面量的成员 ($.ajax({object:"literal"});),因此该对象的方法引用的任何变量都不会被 GC 处理,无论函数对象/方法在哪个上下文中被调用 Here's an answer to a question on closures and scopes,其中包含一些我正在讨论的示例:在另一个上下文中调用对象和闭包引用(关于 self 的位)
    • @EliasVanOotegem 看来我对javascript范围的理解比我想象的要少。我现在正在看一些文章,感谢您指出这一点。
    猜你喜欢
    • 1970-01-01
    • 2018-08-16
    • 2018-11-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-14
    • 2021-01-30
    • 2021-11-05
    • 1970-01-01
    相关资源
    最近更新 更多