简体   繁体   English

当对象在数组中时访问对象属性(javascript)

[英]Accessing Object properties when the object is within an array (javascript)

I am attempting to create an array of objects and then access object properties within the array, but it comes back undefined. 我试图创建一个对象数组,然后访问该数组中的对象属性,但是它回来时未定义。 I call the createObjArray() function and immediately after I do a console.log(objArray[1]); 我调用createObjArray()函数,并在执行console.log(objArray [1]);之后立即调用。 and it prints out the object with all it...s properties just fine. 并打印出具有所有... s属性的对象。 However, if I attempt to do console.log(objArray[1].name); 但是,如果我尝试执行console.log(objArray [1] .name); firebug prints "undefined". 萤火虫打印“未定义”。 Also, when stepping through my code in firebug I can mouse over objArray[1].name and it displays the correct name. 另外,在Firebug中逐步执行代码时,我可以将鼠标悬停在objArray [1] .name上,它会显示正确的名称。 What is happening here, it's driving me nuts. 这里发生的事情,让我发疯。

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;
 }

This will work: 这将起作用:

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.

The problem is that $.getJSON is aynchronous, meaning that it doesn't automatically returns a result. 问题在于$ .getJSON是异步的,这意味着它不会自动返回结果。 Instead, you give it a callback. 而是给它回调。 A callback is a function to execute once it has received a result. 回调是收到结果后立即执行的函数。 In this case, the callback is the anonymous function created when calling $.getJSON. 在这种情况下,回调是调用$ .getJSON时创建的匿名函数。 That callback receives the result from the server, adds it to the array and then checks if the array has been filled. 该回调从服务器接收结果,将其添加到数组中,然后检查数组是否已满。 Since we're doing async code due to the $.getJSON function, we must return the result asynchronously too. 由于我们由于$ .getJSON函数而执行异步代码,因此我们也必须异步返回结果。 To do so, we demand the initObj function to receive a function to call once it has completed (another callback). 为此,我们要求initObj函数接收一个完成后要调用的函数(另一个回调)。 We call that callback and pass it the parameter. 我们调用该回调并将其传递给参数。 We then return the filled array through a callback once again. 然后,我们再次通过回调返回填充的数组。

Your call to $.getJSON is asynchronous. 您对$ .getJSON的调用是异步的。 When initObj() returns p it is still an empty object. 当initObj()返回p时,它仍然是一个空对象。

However initObj() creates a closure which captures a reference to p so when $.getJSON returns p is populated. 但是,initObj()创建一个闭包,该闭包捕获对p的引用,因此在$ .getJSON返回p时填充该闭包。

This is why the object seems empty in code you run immediately after populating the array. 这就是为什么在填充数组后立即运行的代码中对象似乎为空的原因。 However by the time you run your console command the asynchronous calls have returned and the objects are populated. 但是,当您运行控制台命令时,异步调用已返回,并且对象已填充。

You need to wait for all your async calls to return before continuing work on the array. 您需要等待所有异步调用返回,然后才能继续在阵列上工作。 One way to do this would be to increment a counter when you make a call and decrement it when a call returns, then when the final call returns the counter would drop to zero and you continue processing. 一种方法是在拨打电话时增加计数器,在通话返回时减少计数器,然后在最终通话返回时,计数器将降至零,然后继续处理。

Alternatively you could setup a setTimout loop to keep polling the array the check when all its items are populated. 另外,您可以设置setTimout循环,以在填充所有数组项时继续轮询该数组。

Both approaches are risky if you think one of the calls might fail, but the approach itself is fundamentally risky as you are making multiple ajax calls so you have to handle multiple possible failures. 如果您认为其中一个调用可能失败,则这两种方法都是有风险的,但是由于您要进行多个ajax调用,因此该方法本身从根本上来说是有风险的,因此您必须处理多个可能的失败。 It would be a lot cleaner to grab all the data in one go so you can handle success / error states once in the success / error handler in jQuery.ajax. 一次性捕获所有数据将更加干净,因此您可以在jQuery.ajax中的成功/错误处理程序中一次处理成功/错误状态。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM