Array mutation issue

Tell us what’s happening:
Okay so I’ve basically completed by Cash Register project, but I’m hitting a wall. For some reason my cashInDrawer array is being mutated. I cannot figure out how to avoid this. It’s on lines 110, 111, and 112 if you view it in the editor. I’m going to comment below with my console.log results though. If you use ctrl + f and search for “PROBLEM AREA” it should take you to the section.

Basically something about calling the function changeAmount(startingIndex); is causing cashInDrawer to mutate. Below are the solutions I’ve attempted:

  • Not directly refering to cid inside the function, but rather replacing it with cashInDrawer. However, if I then console.log(cid) before and after changeAmount(startingIndex); then cid has mutated.

  • I’ve tried creating the copy of cid inside the function rather than outside.

I finally passed it by moving the function call down into my series of if statements, but I still don’t understand why it was mutating.

Any advice? Does my explanation make any sense?

Your code so far


function checkCashRegister(price, cash, cid) {
var totalInDrawer = getTotal(cid).toFixed(2);
let changeDue = cash - price;
var change = {status: "", change: []};
let cashInDrawer = [...cid];

//console.log(changeDue)

const currencyValues = {
  "PENNY": 0.01,
  "NICKEL": 0.05,
  "DIME": 0.10,
  "QUARTER": 0.25,
  "ONE": 1,
  "FIVE": 5,
  "TEN": 10,
  "TWENTY": 20,
  "ONE HUNDRED": 100,
}
let keys = Object.keys(currencyValues)

//get the total in the drawer
function getTotal (arr) {
  let total = 0;
  for (let i = 0; i < arr.length; i++) {
    total += arr[i][1];
  }
  return total;
}
//get the total in the drawer


//function to get the index to begin substracting change from cid array.
function getStartingPlace (value) {
  let startingPlace;
  let startingValue = 0;
for (let i = 0; i < keys.length; i++){
  if (value > currencyValues[keys[i]]){
    startingValue = currencyValues[keys[i]];
  } else if (value < currencyValues[keys[i]]){
    break;
  }
  
}

switch (startingValue){
case 0.01:
  startingPlace = 0;
    break;
case 0.05:
  startingPlace = 1;
    break;
case 0.10:
  startingPlace = 2;
    break;
case 0.25:
  startingPlace = 3;
    break;
case 1:
  startingPlace = 4;
    break;
case 5:
  startingPlace = 5;
    break;
case 10:
  startingPlace = 6;
    break;
case 20:
  startingPlace = 7;
    break;
case 100:
  startingPlace = 8;
    break;
}
return startingPlace
}
//End of the starting place function

function getCurrentValue (x) {
return currencyValues[keys[x]];
}



let startingIndex = getStartingPlace(changeDue)

function changeAmount (y) {
let cashInDrawer
var emptyChangeArray = [["PENNY", 0], ["NICKEL", 0], ["DIME", 0], ["QUARTER", 0], ["ONE", 0], ["FIVE", 0], ["TEN", 0], ["TWENTY", 0], ["ONE HUNDRED", 0]];
let currentIndex = y;
let amountOwed = changeDue
let currentValue = getCurrentValue(y);
while (currentIndex >= 0) {
while (amountOwed.toFixed(2) >= currentValue) {
  if (cid[currentIndex][1] == 0){
    break;
  }
  amountOwed -= currentValue;
  emptyChangeArray[currentIndex][1] += currentValue;
  cid[currentIndex][1] -= currentValue;
  //console.log(amountOwed)
}
currentIndex -=1;
currentValue = getCurrentValue(currentIndex);
}


return emptyChangeArray;
}
//PROBLEM AREA BELOW
console.log(cashInDrawer) // [ [ 'PENNY', 0.5 ],
let test = changeAmount(startingIndex);
console.log(cashInDrawer) //[ [ 'PENNY', -3.0878077872387166e-16  ],
//PROBLEM AREA ABOVE

function getChange (arr) {
var change = {status: "OPEN", change: []}

for (let i = 0; i < arr.length; i++) {
if (arr[i][1] > 0) {
  change.change.unshift(arr[i])
}
}
return change;
}

//console.log(changeDue + "change due")
//console.log(getTotal(test).toFixed(2) + "Total Change")
//console.log(getTotal(test).toFixed(2) !== changeDue)
//console.log(getChange(test));
//console.log(getTotal(test).toFixed(2) < changeDue)
if (totalInDrawer < (cash - price )) {
  return {status: "INSUFFICIENT_FUNDS", change: []};
} else if (totalInDrawer == (cash - price )) {
  change.status = "CLOSED";
  change.change = cid;
  return change;
} else {
  if (getTotal(test).toFixed(2) < changeDue) {
    return {status: "INSUFFICIENT_FUNDS", change: []};
  } else {
    return getChange(test);
  }
  
}

}

checkCashRegister(19.5, 20, [["PENNY", 0.5], ["NICKEL", 0], ["DIME", 0], ["QUARTER", 0], ["ONE", 0], ["FIVE", 0], ["TEN", 0], ["TWENTY", 0], ["ONE HUNDRED", 0]]);
console.log(checkCashRegister(19.5, 20, [["PENNY", 0.5], ["NICKEL", 0], ["DIME", 0], ["QUARTER", 0], ["ONE", 0], ["FIVE", 0], ["TEN", 0], ["TWENTY", 0], ["ONE HUNDRED", 0]]))

Your browser information:

User Agent is: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.102 Safari/537.36.

Challenge: Cash Register

Link to the challenge:

maybe use const for cashInDrawer?

it’s a multidimensional array, it’s copying the elements inside, but the elements inside are references to other arrays that are not being copied and when modified it will modify all the other places where that reference exist
you need to copy also the inner arrays:

possibilities:

let copy = arr.map(x => x.slice())
let copy = arr.map(x => [...x])
let copy = arr.map(x => arr.concat([]))
let copy = JSON.parse(JSON.stringify(arr)) // only one that works with any arrays of any depth
1 Like

Oh okay that makes sense! Thank you for the explanation and the possible work arounds!