当引用类型的数据作为函数参数传入时, 如何编写可以不改变源数据?

<template>
  <div>
    <button @click="handleClick">点击</button>
  </div>
</template>

<script>
export default {
  data () {
    return {
      myData: {
        name: 'x',
        list: [{ name: 'China' }, { name: 'England' }, { name: 'America' }]
      }
    }
  },
  methods: {
    handleClick () {
      this.funA()
    },
    async funA () {
      const myDateNew = { ...this.myData }
      myDateNew.age = 23
      const data2 = await this.funB(myDateNew)
      // 下面3个属性输出的list都是相同的
      // 当引用数据类型作为函数参数时, 该如何改, 才不会改变了源数据 this.myData 中list的数据
      console.log('myData', this.myData, myDateNew, data2)
    },
    funB (data) {
      const newData = { ...data }
      newData.list.forEach(element => {
        element.num = Math.ceil(Math.random() * 100)
      })
      return newData
    }
  }
}
</script>
阅读 3.3k
4 个回答

首先,myData 是一个对象的引用,所以 { ... this.myData } 成功地产生了一个新对象,其属性与 myData 相同,但它的确和 myData 是不同的对象。我们假设给一个变量叫 x 给它,也就是

const x = { ...myData }

现在,x.list === myData.list 的结果是 true,因为它们引用的同一个对象(数组)。

要想不改变这个数组,需要

x.list = [...myData.list]

问题是,虽然是两个不同的数组了,但是它们内部仍然引用的是相同的对象,比如 x.list[0] === myData.list[0] ……

所以,你这个问题实际是涉及到了“深拷贝”的问题,搜一搜,或者看看这个有点关系的回答

本质的方法只有对原有对象进行深拷贝,复制出一个真正克隆的对象,然后对克隆对象进行操作。

如果只有简单对象的话 可以用 JSON.parse(JSON.stringify(mix)) 做深拷贝

      myData: {
        name: 'x',
        list: [{ name: 'China' }, { name: 'England' }, { name: 'America' }]
      }

加上myData,题主这里是3层引用类型的数据结构
...运算的方式只能做浅拷贝,拷贝最外层,里面的引用类型地址值指向仍旧没有改变。二次修改会导致元数据变化。
建议题主使用 深拷贝

已参与了 SegmentFault 思否「问答」打卡,欢迎正在阅读的你也加入。
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题