简体   繁体   中英

Adding property in nested for-loop causes same values for each parent for-loop

I have an array containing information on playing cards (cardInfo). A sample of the array is added in the code below. Since each card may have duplicates, I want to use this information to create a deck by pushing its information to a new array (drawPile) for each card of that type (the property 'frequency1').

var common = 4;
var uncommon = 3;
var rare = 2;
var cardInfo = [
    {name:'Card A',frequency1:common,frequency2:rare,frequency3:0}, 
    {name:'Card B',frequency1:common,frequency2:uncommon,frequency3:0},
    {name:'Card C',frequency1:uncommon,frequency2:uncommon,frequency3:0}
];

var drawPile = [];
for (var cType = 0; cType < cardInfo.length; cType++) {
    for (var freq = 0; freq < cardInfo[cType].frequency1; freq++) {
        drawPile.push(cardInfo[cType]);
        console.log(drawPile.length - 1);
        drawPile[(drawPile.length - 1)].id = (drawPile.length - 1);
        console.log(drawPile[(drawPile.length - 1)]);
    }
}

The resulting console log, however, shows that all 4 "Card A" cards have the id property 3, all 4 "Card B" cards have the id property 7, and all 3 "Card C" cards have the id property 10. It is as if the nested (freq) loop only runs for all .push() commands before it adds the id property.

More strangeness: when I run this code in jsfiddle , I can replicate these results if I first run it and then open the console log, but when I run it after the console lof is already open, it works as intended.

How do I ensure each card gets a unique identifier?

EDIT: It gets even stranger when I get the exact same results if I create a completely new for loop specifically for adding the id property as seen in this code .

As you loop around the cardInfo collection, for each cardInfo instance, you loop around the frequencies. Technically for each frequency you are pulling in the same instance of the cardInfo , so technically you are updating the same cardInfo instance for each frequency iteration. Now your next statement will be but I write console.log for each iteration. But when you debug the code, console.log outputs correctly, however I'm not sure whether this is the case when it is run through without a debug. So how can you resolve this?

After determining that it was modifying the same instance for each iteration of the related frequency, I decided to clone the card (I'm not saying this is a great idea, but it proves the concept). I achieved this by using:

JSON.parse(JSON.stringify(cardInfo[cType]));

Again this is not the most performant way of achieving this, but highlights where I believe the issue lies.

I have applied this change to a fiddle (I've also simplified the code a little) and if you remove the cloning it operates as you currently see it, but with the cloning it works as you would expect it.

I hope that helps

You are pushing object reference to the drawPile array in the loop. That's why all "Card A" cards have the same ID as array contains same reference. you have to clone the object before pushing into the loop. You can make the below change to your code.

  for (var freq = 0; freq < cardInfo[cType].frequency1; freq++) {
            drawPile.push(JSON.parse(JSON.stringify(cardInfo[cType])));
            console.log(drawPile.length - 1);
            drawPile[(drawPile.length - 1)].id = (drawPile.length - 1);
            console.log(drawPile[(drawPile.length - 1)]);
        }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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