简体   繁体   中英

Why modifying array.slice() also changes the original array?

I am trying to modify a copied array without changing the original one. This is what I've tried, by using slice() method, but it doesn't work as expected:

 //toFill holds the values I want to add into an array named secondArr, //replace every empty sting within secondArr with 0 var toFill = [0, 0, 0, 0]; var mainArr = [ [" ", 1, 1, 1], [" ", 1, 1, 1], [" ", 1, 1, 1], [" ", 1, 1, 1] ]; var secondArr = mainArr.slice(0,4); //this function returns a 1D array, stores the indices of all empty strings within an array function findBlankSpaces(secondArr) { var emptyIndices = []; var innerArrLen = secondArr.length; var outterArrLen = secondArr[0].length; for (var i = 0; i < innerArrLen; i++) { for (var j = 0; j < outterArrLen; j++) { if (secondArr[i][j] == " ") { emptyIndices.push([i, j]); } } } return emptyIndices; } //this function returns the modified array, with empty spaces replaced with 0s function fillWithZero(secondArr, toFill) { var emptyIndices = findBlankSpaces(secondArr); for (var i = 0; i < emptyIndices.length; i++) { secondArr[emptyIndices[i][0]][emptyIndices[i][1]] = toFill[i]; } } //consoles console.log(fillWithZero(secondArr, toFill)); console.log(mainArr); //expected output in console is [[" ", 1,1,1], [" ",1,1,1], [" ",1,1,1], [" ",1,1,1]]; //actual output is [[0,1,1,1], [0,1,1,1], [0,1,1,1], [0,1,1,1]]; //I didn't modify mainArr, but only modified secondArr, why that mainArr also affected? 

I didn't modify the mainArr , only created a copy by using slice() , but why it keeps changing when its copy changes?

This question is: Any way to stop this from happening or how do I call the mainArr again without any 0s in it, I want mainArr stays unchanged. Thanks

As shown at Slice MDN , the slice method returns a shallow copy of the array that calls it. Deep copy discusses a few ways to deep copy objects in JS. A good one it mentions is

var secondArr = JSON.parse(JSON.stringify(mainArr))

This converts your array to JSON and then parses it into a new object

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

The slice() method returns a shallow copy of a portion of an array into a new array object

The key word here is shallow .

mainArr is an array of arrays, so while slice will give you a new copy of the outer array, the array it gives you contains references to the items in mainArray so when you modify them you are actually modifying the items in mainArray .

You could deep-clone mainArr, but it's likely going to be more efficient to only replace the bits you need.

This works, though it could be made cleaner. One option would be to use immer to make the modifications.

 //replace every empty sting within secondArr with 0 var toFill = [0, 0, 0, 0]; var mainArr = [[" ", 1, 1, 1], [" ", 1, 1, 1], [" ", 1, 1, 1], [" ", 1, 1, 1]]; //this function returns a 1D array, stores the indices of all empty strings within an array function findBlankSpaces(arr) { var emptyIndices = []; var innerArrLen = arr.length; var outterArrLen = arr[0].length; for (var i = 0; i < innerArrLen; i++) { for (var j = 0; j < outterArrLen; j++) { if (arr[i][j] == " ") { emptyIndices.push([i, j]); } } } return emptyIndices; } //this function returns the modified array, with empty spaces replaced with 0s function fillWithZero(mainArr, toFill) { var emptyIndices = findBlankSpaces(mainArr); let newArr = [...mainArr]; emptyIndices.forEach(indic => { newArr[indic[0]] = [ ...mainArr[indic[0]].slice(0, indic[1]), toFill[indic[1]], ...mainArr[indic[0]].slice(indic[1] + 1) ]; }); return newArr; } //consoles console.log(fillWithZero(mainArr, toFill)); console.log(mainArr); 

If you apply the slice method to an array which contains arrays, the sub-arrays are copied by reference. Anything you add to the copy will be added to the original array containing arrays.

Array and object always have a reference to the parent when a copy is made. That is when we copy array a to array b , changes made in array b also affect in array a because b has a reference to a .

To overcome this issue, we can use spread operator ( ... )

please check the snippet below

 var a = [1,2,3,4,5,6]; var b = a; console.log('First array ', a); console.log('Second array ', b); // lets remove an element from b and check b.splice(1,1); console.log('Second array after splicing', b); console.log('First array after splicing', a); // Here value in the index 1 is missing in both the array. // to prevent this we can use spread operator var a = [1,2,3,4,5,6]; var b = [...a]; console.log('First array ', a); console.log('Second array ', b); // lets remove an element from b and check b.splice(1,1); console.log('Second array after splicing using spread operator', b); console.log('First array after splicing using spread operator', a); 

The slice() method returns a shallow copy of a portion of an array into a new array object selected from begin to end (end not included) where begin and end represent the index of items in that array. The original array will not be modified.

Please refer this link:

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

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