为什么修改array.slice()也会更改原始数组?

时间:2019-03-06 03:38:55

标签: javascript arrays node.js

我试图在不更改原始数组的情况下修改复制的数组。这是我通过使用slice()方法尝试过的方法,但没有按预期工作:

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

我没有修改 mainArr ,仅使用slice()创建了一个副本,但是为什么当副本更改时它会不断更改?

这个问题是:任何阻止这种情况发生的方法,或者如何再次调用 mainArr ,我没有任何0希望 mainArr 保持不变。谢谢

5 个答案:

答案 0 :(得分:2)

Slice MDN所示,slice方法返回调用它的数组的浅表副本。 Deep copy讨论了在JS中深度复制对象的几种方法。它提到的一个很好的是

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

这会将您的数组转换为JSON,然后将其解析为新对象

答案 1 :(得分:2)

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

  

slice()方法将数组的一部分的浅表副本返回到新的数组对象中

这里的关键词是shallow

mainArr是一个数组数组,因此尽管slice将为您提供外部数组的新副本,但它为您提供的数组包含对mainArray中各项的引用。您修改它们实际上是在修改mainArray中的项目。

您可以深度克隆mainArr,但是仅替换所需的位可能会更有效率。

这可以工作,尽管可以使其更清洁。一种选择是使用immer进行修改。

//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);

答案 2 :(得分:2)

如果将切片方法应用于包含数组的数组,则会通过引用复制子数组。您添加到副本中的所有内容都会添加到包含数组的原始数组中。

答案 3 :(得分:1)

复制副本时,

Arrayobject始终具有对父级的引用。 那就是当我们将array a复制到array b时,在array b中所做的更改也会影响array a,因为b引用了a。 / p>

要解决此问题,我们可以使用传播运算符(...)

请检查下面的代码段

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

答案 4 :(得分:0)

slice()方法将数组的一部分的浅表副本返回到从开始到结束(不包括end)的新数组对象中,其中begin和end表示该数组中项的索引。原始数组将不会被修改。

请参考此链接:

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