使用展开运算符复制数组后,通过map方法对其操作为什么会修改原始数组?

4
  1. 当使用展开运算符复制数组,并通过map方法运行时,为什么会修改原始数组?

  2. 在这里我应该怎么做才能不改变原始数组?

    const data = {hello : "10"};
    const prop = [{name : "hello", color: "red", value : ""}]
    
    const copyProp = [ ...prop ]
    
    copyProp.map(el => {
     el.value = data[el.name] || ""
       return el
    }) // 
    
    console.log(copyProp === prop) // -> false
    console.log(copyProp) // -> value: 10
    console.log(prop) // -> Value: 10 (Should still be "")


你正在复制数组,而不是复制你改变的对象。 - Bergi
2个回答

5

扩展运算符创建数组的浅拷贝。换句话说,您创建一个新数组,并引用相同对象。因此,当您修改这些对象时,更改将反映在原始数组中。

通常,在需要复制数组时,应考虑进行深拷贝。但在这种情况下,您只需要正确使用 map()map() 创建一个新数组,因此它可以直接为您创建修改后的副本:

const copyProps = props.map(el => {
        return {
            ...el,
            value: data[el.name] || '',
        }
});

这里使用spread运算符复制每个对象。这意味着生成的数组具有自己的对象引用。这与您原始解决方案存在相同的注意事项:这是浅拷贝。对于您的示例数据,这没问题,因为所有值和键都是字符串。但是,如果您的实际数据更深层嵌套,包含更多的数组和对象,您将遇到相同的问题。


有很多文章声称使用扩展运算符时,数组是没有引用的克隆,但它们真的应该提到这种边缘情况。当我的时间到了,我会接受这个答案,谢谢。 - Terry
@Terry,你能给一个这样的文章链接吗?我不知道“没有引用的克隆”是什么意思。这不是边缘情况。这正是展开运算符的工作方式。 - Code-Apprentice

1

数组和对象都是通过引用传递的,因此当你展开一个数组时,你创建了一个新的数组,但是填充了对原始对象的引用。当你在新数组中修改这些对象时,你仍然修改了在两个数组中都引用的内存中的相同数据。

另外,map方法总是返回一个新数组,所以在这种情况下,你只需要克隆对象,由于这里没有深度嵌套的对象,所以可以使用对象展开语法。

const data = {
  hello: "10"
};

const prop = [{
  name: "hello",
  color: "red",
  value: ""
}]

const copyProp = prop.map(el => ({ ...el,
  value: data[el.name] || ''
}))
console.log(copyProp)
console.log(prop)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接