简体   繁体   中英

Why does mutating one array somehow mutate another?

I have created a function that is designed to merge multiple multidimensional arrays together

The input 'table' is currently 2 arrays contained in objects, the function is designed to run each time a command is run(not very efficient I know, but it is for a highschool project where this is required)

Printing the input looks like:

[ [ [ 'a', 1 ], [ 'b', 1 ] ], [ [ 'a', 1 ] ] ]

Expecting the resulting table to look like this every time I would run the function:

[ [ 'a', 2 ], [ 'b', 1 ] ]

Instead of incrementing 'tempTable[u][1]' it increments the array connected to table[0] of the input.

Printing the original array which was [ [ 'a', 1 ], [ 'b', 1 ] ] would now show 'a' incrementing by 1 each time the code was run.

I have no idea why it is incrementing the original array instead of just 'tempArray' each time, would somebody be able to explain to me why it increments the original table?

PS It is the fault of this function, if I comment out the line that should increment 'tempTable' by 1, the original table doesn't change.

 function combineTable(table) { var tempTable = table[0]; for (var i = 1; i < table.length; i++) { //each table for (var u = 0; u < tempTable.length; u++) { //temptable values for (var y = 0; y < table[i].length; y++) { //current table values if (tempTable[u][0] === (table[i])[y][0]) { tempTable[u][1] += (table[i])[y][1]; } else { console.log("Not contained"); } } } } } combineTable([ [ ['a', 1], ['b', 1] ], [ ['a', 1] ] ])

You need to use the Array.prototype.slice() method for each nested array.

So instead of var tempTable = table[0]; , you need to use:

var tempTable = table[0].map(arr => arr.slice());

You can't just say thing = arr[0] for a multidimensional array because that just returns a reference to the value, not a copied value.

 function combineTable(table) { var tempTable = table[0].map(arr => arr.slice()); // This is the line changed for (var i = 1; i < table.length; i++) { //each table for (var u = 0; u < tempTable.length; u++) { //temptable values for (var y = 0; y < table[i].length; y++) { //current table values if (tempTable[u][0] === (table[i])[y][0]) { tempTable[u][1] += (table[i])[y][1]; } else { console.log("Not contained"); } } } } // Adding console logging for demo console.log(table); console.log(tempTable); } combineTable([ [ ['a', 1], ['b', 1] ], [ ['a', 1] ] ])

note: I wrote this answer because I thought the accepted answer didn't clearly answer your question of why modifying one array changed another.

Modifying array A also modifies array B if array A and B are references to the same array.

const arrayA = [1]
const arrayB = arrayA;
arrayB[0] = 2;
console.log(arrayA, arrayB); // -> [2]   [2]

JavaScript uses a call by sharing strategy for objects, which applies to arrays since in JavaScript an array is a type of object. How to mutate objects while avoiding side-effects such as mutating other objects depends on the kind of data within the array.

Because JavaScript uses pass by value for primitives, we can do the following:

const array2D = [[1]];
const array1D = [ array2D[0][0] ];
array1D[0] = 2;
console.log(array2D, array1D); // -> [[1]]   [2]

Though, if the array contains other arrays, then our problem is reproduced.

const array3D = [[[1]]];
const array2D = [ array3D[0][0] ];
array2D[0][0] = 2;
console.log(array3D, array2D) // -> [[[2]]]   [[2]]

Essentially, if you're mutating an object's property, be careful of what references exist to that that object. If I write JavaScript with this in mind, then I find I don't run into issues about this very often.

If you're in a serious bind, you can deep clone an object to produce a new object without any references. There's catches to this, here's an answer that shows how a deep clone function could be built and the problems with it: How to Deep clone in javascript

And lodash provides a utility for it _.cloneDeep()

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