【问题标题】:Accessing Object properties when the object is within an array (javascript)当对象在数组中时访问对象属性(javascript)
【发布时间】:2012-11-06 23:18:27
【问题描述】:

我试图创建一个对象数组,然后访问数组中的对象属性,但它返回未定义。我调用 createObjArray() 函数,并在我执行 console.log(objArray[1]); 之后立即调用它打印出具有所有属性的对象就好了。但是,如果我尝试执行 console.log(objArray[1].name);萤火虫打印“未定义”。此外,在 firebug 中单步执行我的代码时,我可以将鼠标悬停在 objArray[1].name 上,它会显示正确的名称。这里发生了什么,这让我发疯了。

var objArray = [];

function createObjectArray(numOfObjs) {

    for(var i=0; i<numOfObjs; i++) {

packages.push(initObj(i)); 

    }
 }

function initObj(i){
    var newPackage;
    var p = {};
    $.getJSON('.../package' + i + '.json', function(data) {
        newPackage = new Package(data);
        p.name = newPackage.name;
        p.id = i;      
    });
    return p;
 }

【问题讨论】:

  • $.getJSON 是否进行异步调用?如果是这样,当 initObj 方法返回时 p 将为空。
  • 它使用 console.log(arrayObj[1]) 正确打印对象。它在其中打印整个对象,如下所示:Object { name="my name", id=1}。所以 P 回来了
  • 这是因为 p 是稍后设置的,从异步调用返回时。您正在 initObj 中创建一个闭包,该闭包捕获对 p 的引用。我从文档中看到 $.getJSON 是异步的。所以这段代码有问题,在异步调用返回之前 p 是一个空对象。
  • 我该如何解决这个问题?感谢您的快速回答。

标签: javascript


【解决方案1】:

这将起作用:

var objArray = [];

function createObjectArray(numOfObjs, callback) {
    var filledPackage = [];
    var nbLeft = numOfObjs;
    for(var i=0; i<numOfObjs; i++) {
        initObj(i, function(p){
            filledPackage.push(p);
            nbLeft--;
            if (nbLeft === 0){
                callback(filledPackage);
            }
        }); 
    }
 }

function initObj(i, callback){
    var newPackage;
    var p = {};
    $.getJSON('.../package' + i + '.json', function(data) {
        newPackage = new Package(data);
        p.name = newPackage.name;
        p.id = i;     
        callback(p);
    });
}

//Get a filled object array:
createObjectArray(5, function(filledArray){
    objArray = filledArray;
    //Code here will be executed AFTER all the $.getJSON queries have returned.
    //objArray is not empty.
});
//Code here will be executed WHILE the getJSON queries are running and
//while objArray is still empty. Due to the way the JS event loop works,
//it is impossible that code placed here will be able to use the content
//of objArray unless you call an async function such as anything AJAX or
//setTimeout, but that's iffy. Code you want to be executed once objArray
//has been filled should be inside of the callback above.

问题在于 $.getJSON 是异步的,这意味着它不会自动返回结果。相反,你给它一个回调。回调是在收到结果后执行的函数。在这种情况下,回调是调用 $.getJSON 时创建的匿名函数。该回调从服务器接收结果,将其添加到数组中,然后检查数组是否已填充。由于 $.getJSON 函数我们正在执行异步代码,因此我们也必须异步返回结果。为此,我们要求 initObj 函数接收一个在完成后调用的函数(另一个回调)。我们调用该回调并将参数传递给它。然后我们再次通过回调返回填充的数组。

【讨论】:

    【解决方案2】:

    您对 $.getJSON 的调用是异步的。当 initObj() 返回 p 时,它仍然是一个空对象。

    但是 initObj() 创建了一个闭包,它捕获对 p 的引用,因此当 $.getJSON 返回时 p 被填充。

    这就是为什么在填充数组后立即运行的代码中对象看起来为空的原因。但是,当您运行控制台命令时,异步调用已返回并且对象已被填充。

    在继续处理阵列之前,您需要等待所有异步调用返回。一种方法是在您进行调用时增加一个计数器,并在调用返回时减少它,然后当最终调用返回时,计数器将降至零并继续处理。

    或者,您可以设置一个 setTimout 循环,以在填充所有项目时继续轮询数组检查。

    如果您认为其中一个调用可能会失败,这两种方法都是有风险的,但这种方法本身存在根本风险,因为您要进行多个 ajax 调用,因此您必须处理多个可能的故障。一次抓取所有数据会更干净,这样您就可以在 jQuery.ajax 的成功/错误处理程序中处理成功/错误状态。

    【讨论】:

    • 我将尝试在 $.getJSON 之后调用一个函数来处理数组。谢谢!
    • 阅读您的编辑。谢谢,我将不得不研究如何以正确的方式做到这一点。
    猜你喜欢
    • 2013-12-02
    • 1970-01-01
    • 1970-01-01
    • 2019-10-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-12
    • 2017-10-15
    相关资源
    最近更新 更多