Cash Register - Why does the original array(cid) change?

Cash Register - Why does the original array(cid) change?
0

#1

Tell us what’s happening:

I copied the original array(cid) into dupCid variable using slice method. But after the program runs it changed both the array(cid &dupCid). Please help me.

Your code so far


function checkCashRegister(price, cash, cid) {
    var dupCid = cid.slice();
    var change = cash - price;
    // Here is your change, ma'am.
    let quantity = 0, stat, returnArr = [];
    var chkslab = function () {
        if( dupCid[8][1] && change > 100) {
            chkBalance(dupCid[8], 100);
        }
    
        console.log(change);
    
        if( dupCid[7][1] && change > 20) {
            chkBalance(dupCid[7], 20);
        }
    }();
    

    function chkBalance(arrValue, slab) {
        quantity = (Math.floor(change / slab)) * slab;
        change = change % slab;
        if(quantity > arrValue[1]) {
            change += quantity - arrValue[1];
            returnArr.push([arrValue[0], arrValue[1]]);
        }else {
            returnArr.push([arrValue[0], quantity]);
            arrValue[1] -= quantity;
        }
    }

    console.log(dupCid);
    console.log(cid);
    return returnArr;
}




console.log(checkCashRegister(19.5, 140, [["PENNY", 1.01], ["NICKEL", 2.05], ["DIME", 3.1], ["QUARTER", 4.25], ["ONE", 90], ["FIVE", 55], ["TEN", 20], ["TWENTY", 60], ["ONE HUNDRED", 100]]));
//checkCashRegister();

Your browser information:

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

Link to the challenge:
https://learn.freecodecamp.org/javascript-algorithms-and-data-structures/javascript-algorithms-and-data-structures-projects/cash-register/


#2

The problem is that while slice gives you a new array, i.e., cid and dupCid are NOT the same arrays, the slice operation only copies object references instead of giving you different objects in the new array. So, you have two different arrays, but both have the same references to the underlying objects (arrays) in cid, so when you change the underlying object in one it changes in the other since they both point to the same (changed) object.

See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/slice for more info.


#3

Should not slice give a new array? I mean not the reference. Even concat(), spread[…] operator does not work. So how do i copy then?


#4

I found a solution from stackoverflow.
var newArray = JSON.parse(JSON.stringify(orgArray));
Here is the link: https://stackoverflow.com/questions/7486085/copying-array-by-value-in-javascript
If you guys know better solution tell me.


#5

Yes, as I wrote, slice does give a new array. You can even check yourself, try cid === dupCid and it will return false. The arrays are different, with the elements copied from one to the other, but the question is what were the elements that were copied?

When you slice the array [1, 'string' , true] you will get a new array [1, 'string', true] where each value is copied as its plain value. Change a value in one array and nothing changes in the other. The integer 1 is not a reference to a “1 integer” thing stored deep in the JavaScript memory, it’s just an integer, so both arrays contain an integer 1, and if you change one of them you don’t change the other because they are just integer values, etc…

However, when an element in the array is an object, the element in the array is a reference (or pointer) to that object, not the object itself (this is how objects are treated in JavaScript, they are not stored by value, they are stored as references to the object - see the bottom of this page for more info). So when slice copies the ‘object’ to the new array, it sends what it sees in the array, which is just a reference to the object and NOT the object values. So now both arrays have a reference to the same object, and when you change that object (in either array OR anywhere outside the arrays even) you are changing the object itself and NOT the references in the arrays, so both arrays will reference this same object, which has changed.

This is visible if you just make two objects that look equal. Set obj1 = {name: 'object'} and obj2 = {name: 'object'}. Now try obj1 === obj2. They look equal, but this returns false because obj1 is really a reference to your object with key name and value ‘object’, whereas obj2 is a (different) reference to a different object with key name and value ‘object’. (This is also why cid === dupCid is false after slicing, they are both references, but to different objects with the same values.)

So why is this only for objects and not for the [1, 'string', true] array above? Objects are mutable, you define an object and very frequently want to change it later, so you can change whatever is at the end of the reference but the reference always stays the same. (I.e., you are changing the object itself instead of changing a value and getting a different object back.) However, the integer 1 shouldn’t act like this. If you add 1 to the integer 1 you shouldn’t get the same integer 1 with a mutated value of 2, you should really get a new and different integer 2. Similarly for strings and booleans, it doesn’t make sense to mutate them so they are stored as their values with nothing hidden behind the scenes.


#6

Yeah, now i realize. Thanks @mathic .