最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Why modifying array.slice() also changes the original array? - Stack Overflow

programmeradmin0浏览0评论

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 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

Share Improve this question edited Mar 6, 2019 at 3:53 WWL asked Mar 6, 2019 at 3:38 WWLWWL 1652 silver badges10 bronze badges 3
  • 2 "I didn't modify the mainArr, only created a copy by using slice(), but why it keeps changing when its copy changes?" Refer to .slice(): "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). The original array will not be modified." You need to specify the index (arr.slice([begin[, end]])) – Mukyuu Commented Mar 6, 2019 at 3:47
  • 1 array and object always have a reference to the parent when a copy is made. so when ever a change occur it will affect both – Akhil Aravind Commented Mar 6, 2019 at 3:51
  • 1 Do this: var secondArr = JSON.parse(JSON.stringify(mainArr)); – Ponleu Commented Mar 6, 2019 at 3:56
Add a comment  | 

5 Answers 5

Reset to default 8

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

发布评论

评论列表(0)

  1. 暂无评论