You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Vue3中过滤响应式数组后修改新数组为何会更新原数组?

Vue3中过滤响应式数组后修改新数组元素影响原数组的原因分析

核心原因:数组元素是对象引用,而非独立副本

JavaScript的filter方法确实会创建一个全新的数组实例,但这个新数组中的元素并非原数组对象的深拷贝——它们是原数组中符合条件对象的内存引用。也就是说,新旧数组里的对应元素指向的是同一个对象实例,修改其中一个的属性,本质上就是修改这个对象本身,自然会同步反映到原数组的对应元素上。

结合Vue3响应式的补充说明

Vue3基于Proxy实现响应式系统,当你将一个数组通过reactive转为响应式后,数组内的对象也会被转为响应式对象(默认是浅响应式)。无论你是从原响应式数组,还是从过滤后的新数组访问这个对象,操作的都是同一个响应式对象。修改对象属性时,Proxy会捕获到这个变化并触发视图更新,原数组的元素自然也会同步变化。

示例代码验证(模拟问题场景)

假设你有如下响应式数组:

import { reactive } from 'vue'

const originalList = reactive([
  { id: 1, name: 'Vue', completed: false },
  { id: 2, name: 'React', completed: true },
  { id: 3, name: 'Angular', completed: true }
])

// 过滤得到新数组
const filteredList = originalList.filter(item => item.completed)

// 修改新数组元素的属性
filteredList[0].completed = false

// 此时原数组的第二个元素(id=2)的completed也会变为false
console.log(originalList[1].completed) // 输出: false

解决办法:对元素进行深拷贝

如果希望过滤后的新数组元素与原数组完全独立,需要对每个元素执行深拷贝,切断引用关系。常见的实现方式有:

  • 使用原生API structuredClone(支持大多数数据类型,包括循环引用):
    const filteredList = originalList.filter(item => item.completed).map(item => structuredClone(item))
    
  • 使用JSON.parse(JSON.stringify(item))(注意:无法处理函数、Symbol、循环引用等特殊类型):
    const filteredList = originalList.filter(item => item.completed).map(item => JSON.parse(JSON.stringify(item)))
    
  • 使用Vue提供的cloneDeep工具(从@vue/shared包导入):
    import { cloneDeep } from '@vue/shared'
    
    const filteredList = originalList.filter(item => item.completed).map(item => cloneDeep(item))
    

内容的提问来源于stack exchange,提问作者Craig

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 07:31:06