1

so I have been staring at this issue for some time now and I cannot understand what is going wrong. I am trying to create the game Yahtzee, and I have a function that will randomly generate the 5 dice. This function is also reused when the user wishes to roll again. I pass in an array of objects, each object has a number property representing what the user rolled. I ran into this issue where the loop I have to generate a new dice set, does not replace the old one. Here is my function code

function roll(theRoll){
    diceSet = theRoll;

    console.log("before")
    console.log(diceSet)

    for(let i = 0; i < diceSet.length; i++){
        if(diceSet[i].isHeld == false){
            diceSet[i].number = Math.floor((Math.random() * 6) + 1);
        }
        
        document.getElementById("die" + (i + 1) + "Img").src = "img/" + diceSet[i].number + ".png";
    } 
   
    console.log("After")
    console.log(diceSet)
    return theRoll;


}

Now I could be wrong but the code above should work fine but my "diceSet" has the same numbers before and after the loop, but I dont have any clue why the properties are not changing.

Here is my output enter image description here

Any help would be appreciated thank you

MT0
  • 143,790
  • 11
  • 59
  • 117
  • Maybe try deep cloning `theRoll` before assigning it to diceSet. You can use a library like https://github.com/davidmarkclements/rfdc or just implement the deep clone yourself. – ElectricShadow Oct 01 '20 at 00:28
  • It seems weird,I tried myself and got different result each time,can you provide us a demo in jsfiddle? – flyingfox Oct 01 '20 at 00:28
  • It also varies by browser.. alas, could be made more consistent – user2864740 Oct 01 '20 at 00:43
  • So when I had this issue I was using chrome, also ElectricShadow, I would love to use a library to clone, however, due to performance issues of the project I can't use any external libraries –  Oct 02 '20 at 01:11

2 Answers2

2

The values are changing; its just that you are logging the values to the console and the console is showing the current values of the array (at the time you view it) and not the values in the array at the instant it was logged. If you want to see the change in values then convert the array to a string rather than logging the array.

function diceToString(theRoll)
{
  return theRoll.map(roll => roll.number).join(",");
}

function roll(theRoll){
    console.log("before")
    console.log(theRoll)
    console.log(diceToString(theRoll))

    for(let i = 0; i < theRoll.length; i++){
        if(theRoll[i].isHeld == false){
            theRoll[i].number = Math.floor((Math.random() * 6) + 1);
        }
        
        document.getElementById(`die${i + 1}Img`).src = `img/${theRoll[i].number}.png`;
    } 
   
    console.log("After")
    console.log(theRoll)
    console.log(diceToString(theRoll))
    return theRoll;
}

dice = [
  {"isHeld": false, "number": 0},
  {"isHeld": false, "number": 0},
  {"isHeld": false, "number": 0},
  {"isHeld": false, "number": 0},
  {"isHeld": false, "number": 0}
]

roll(dice);
roll(dice);
roll(dice);
roll(dice);
<img id="die1Img" src="" alt="" />
<img id="die2Img" src="" alt="" />
<img id="die3Img" src="" alt="" />
<img id="die4Img" src="" alt="" />
<img id="die5Img" src="" alt="" />

You can also run the snippet and see the output (and the values changing) and then compare it to the log in the browser console to see the difference.

MT0
  • 143,790
  • 11
  • 59
  • 117
  • Ok that's good to hear, I was worried it was not changing anything at all. I will change them to strings to view, Thanks for the help! –  Oct 01 '20 at 00:52
0

It's because arrays and objects in JS are mutable, which means that they are copying by reference. In other words, if you pass an object (or an array) into any function (doesn't matter, it is yours or a default one), you actually pass the reference, not a copy.

function addOne(obj) {
  obj.value += 1;
}

function addTwo(obj) {
  obj.value += 2;
}

const testObj = {
  value: 0
}

addOne(testObj);
addTwo(testObj);

console.log(testObj)

testObj had never been reassigned, but the value is equal to 3 finally. When function addTwo was called, it took already updated value (equal to 1). Actually, the same thing happens when you pass mutable entities into console.log method - it takes a reference and you see the "actual" state of your object, not a snapshot at the time of the call.

There is another reason for this behaviour - time gaps. They are briefly covered in this answer (see "More details" block): https://stackoverflow.com/a/30363526/6053654

The simplest way to avoid this behaviour is to convert your data to an immutable type. Strings are perfect for this, and you can simply JSON.stringify your object before logging it into the console.

P.S.
  • 15,970
  • 14
  • 62
  • 86
  • 1
    Ok, thanks for the information, I will keep this in mind if this issue comes up in the future! –  Oct 02 '20 at 01:13