【问题标题】:Javascript - How can I change one list without modifying the other [duplicate]Javascript - 如何在不修改另一个列表的情况下更改一个列表[重复]
【发布时间】:2018-02-19 21:54:36
【问题描述】:

我有以下代码:

const heroes = [
  { name: 'Wolverine',      family: 'Marvel',    isEvil: false },
  { name: 'Deadpool',       family: 'Marvel',    isEvil: false },
  { name: 'Magneto',        family: 'Marvel',    isEvil: true  },
  { name: 'Charles Xavier', family: 'Marvel',    isEvil: false },
  { name: 'Batman',         family: 'DC Comics', isEvil: false },
  { name: 'Harley Quinn',   family: 'DC Comics', isEvil: true  },
  { name: 'Legolas',        family: 'Tolkien',   isEvil: false },
  { name: 'Gandalf',        family: 'Tolkien',   isEvil: false },
  { name: 'Saruman',        family: 'Tolkien',   isEvil: true  }
]

var newHeroes = heroes.slice(0);

newHeroes[0] = { name: 'Test', family: '2', isEvil: false };
newHeroes[1].name = 'Test 2';

console.log(newHeroes);
console.log(heroes);

当我对第一个数组进行切片时,我希望第二个数组是 hero const 的非内存副本。因此,每当我更改 newHeroes 数组时,我认为第一个不会更改。

当我更改整个内容(如 newHeroes[0] = Object)时,它可以完美运行。这只会更改第二个数组。

但是当我尝试直接更改属性时(newHeroes[1].name = 'Test 2'),它在两个数组中都会发生变化。

谁能解释一下为什么?

谢谢! :-)

【问题讨论】:

  • slice() 创建一个浅拷贝,但每个索引仍然指向相同的对象。
  • @PatrickRoberts 索引?你说的是同一个对象吗?
  • lodash 有一个名为 cloneDeep() 的函数用于深拷贝
  • @Ele 是的,谢谢你重复我刚才说的话。
  • @Ele 既然你很困惑,1 是一个索引。我是说newHeroes[1].name = 'Test 2' 修改了heroes[1].name,因为newHeroes 的“每个索引”是对heroes 的每个索引引用的相应对象的引用。我的说法没有错。

标签: javascript arrays


【解决方案1】:

您需要创建数组的深层副本,因为您的数组由对象组成,而这些对象又拥有自己的引用。 Slice 只会创建一个浅拷贝。你可以这样做:

const heroes = [
  { name: 'Wolverine',      family: 'Marvel',    isEvil: false },
  { name: 'Deadpool',       family: 'Marvel',    isEvil: false },
  { name: 'Magneto',        family: 'Marvel',    isEvil: true  },
  { name: 'Charles Xavier', family: 'Marvel',    isEvil: false },
  { name: 'Batman',         family: 'DC Comics', isEvil: false },
  { name: 'Harley Quinn',   family: 'DC Comics', isEvil: true  },
  { name: 'Legolas',        family: 'Tolkien',   isEvil: false },
  { name: 'Gandalf',        family: 'Tolkien',   isEvil: false },
  { name: 'Saruman',        family: 'Tolkien',   isEvil: true  }
]

var newHeroes = heroes.reduce((newArr, hero) => {
  newArr.push({...hero}); // creating a shallow copy of this object
  return newArr;
}, [])

newHeroes[0] = { name: 'Test', family: '2', isEvil: false };
newHeroes[1].name = 'Test 2';

console.log(newHeroes);
console.log(heroes);

【讨论】:

  • 这只会解决浅对象数组的问题。如果任何对象具有嵌套对象,则此方法将失败。需要递归解决方案才能进行深层复制。
  • 是的,这是正确的(请注意,我发表的评论说这是对象的浅拷贝)。我只是在回答他的用例。有一百万个用于创建深层副本的堆栈溢出答案。不过,这对于这个用例来说已经足够了。
猜你喜欢
  • 2015-06-29
  • 1970-01-01
  • 2011-05-19
  • 1970-01-01
  • 2011-04-22
相关资源
最近更新 更多