一、浅拷贝(Shallow Copy)
1. 定义与特点
- 只复制对象的一层属性:若对象的属性是基本类型(如
number、string),则复制其值;若属性是引用类型(如对象、数组),则仅复制引用(内存地址),而非对象本身。 - 新旧对象共享引用类型的属性:修改其中一个对象的嵌套属性,会影响另一个对象。
2. 实现方式
在 Vue 中,常见的浅拷贝方法有:
- 扩展运算符(Spread Operator):
const newObj = {...oldObj}; Object.assign():const newObj = Object.assign({}, oldObj);- 数组方法:
arr.slice()、[...arr]。
3. 示例代码
const original = {
name: "Vue",
version: { major: 3, minor: 2 }
};
const shallowCopy = { ...original }; // 浅拷贝
shallowCopy.version.major = 4;
console.log(original.version.major); // 输出 4,原始对象被修改!
4. 原理图解
原始对象 original
├── name: "Vue"
└── version: ┌── major: 3
└── minor: 2
浅拷贝 shallowCopy
├── name: "Vue" (值复制)
└── version: ┌── major: 3 (引用复制,指向同一内存地址)
└── minor: 2
二、深拷贝(Deep Copy)
1. 定义与特点
- 递归复制对象的所有层级:创建一个完全独立的对象,与原始对象没有任何内存共享。
- 修改新对象不会影响原始对象:无论嵌套多深,所有属性都是独立的。
2. 实现方式
在 Vue 中,实现深拷贝的方法有:
- JSON 序列化与反序列化:
const deepCopy = JSON.parse(JSON.stringify(original));- 局限性:无法处理函数、正则、
Date对象、循环引用等。
- 局限性:无法处理函数、正则、
- 递归函数:手动编写递归逻辑遍历并复制所有属性。
- 第三方库:如
lodash.cloneDeep()、Vuex的clone()工具。
3. 示例代码
const original = {
name: "Vue",
version: { major: 3, minor: 2 },
update: () => console.log("Updated")
};
// 手动实现深拷贝函数
function deepCopy(obj) {
if (obj === null || typeof obj !== "object") return obj;
const clone = Array.isArray(obj) ? [] : {};
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
clone[key] = deepCopy(obj[key]); // 递归复制
}
}
return clone;
}
const deepCopy = deepCopy(original);
deepCopy.version.major = 4;
console.log(original.version.major); // 输出 3,原始对象未被修改
4. 原理图解
原始对象 original
├── name: "Vue"
└── version: ┌── major: 3
└── minor: 2
深拷贝 deepCopy
├── name: "Vue" (值复制)
└── version: ┌── major: 3 (递归创建新对象,内存地址不同)
└── minor: 2
三、Vue 中的特殊场景
1. 响应式数据与拷贝
- 浅拷贝丢失响应式:使用浅拷贝(如
Object.assign())复制 Vue 实例的响应式数据时,新对象的嵌套属性会失去响应式特性。export default { data() { return { user: { name: "Alice", age: 20 } }; }, methods: { updateUser() { // ❌ 浅拷贝,新对象的 age 不再是响应式的 const newUser = Object.assign({}, this.user); newUser.age = 21; // 不会触发视图更新 } } }; - 深拷贝保持响应式:使用
Vue.set()或Vuex的clone()工具进行深拷贝,确保新对象仍具有响应式特性。
2. 循环引用问题
- 深拷贝的陷阱:若对象存在循环引用(如
obj.a = obj),递归深拷贝会导致栈溢出。 - 解决方案:使用
WeakMap记录已处理的对象,避免重复拷贝。function deepCopy(obj, map = new WeakMap()) { if (obj === null || typeof obj !== "object") return obj; if (map.has(obj)) return map.get(obj); // 处理循环引用 const clone = Array.isArray(obj) ? [] : {}; map.set(obj, clone); // 记录已处理的对象 // 递归复制... }
四、性能考量
- 浅拷贝:时间复杂度为
O(n),仅遍历一层属性,性能较高。 - 深拷贝:时间复杂度为
O(m)(m为所有嵌套属性总数),递归操作开销大,慎用在大型数据结构上。
五、总结与最佳实践
| 场景 | 浅拷贝 | 深拷贝 |
|---|---|---|
| 数据隔离需求 | ❌ 不适用(共享引用) | ✅ 完全隔离 |
| 响应式数据处理 | ❌ 可能丢失响应式 | ✅ 使用 Vue 专用工具 |
| 性能敏感场景 | ✅ 高效 | ❌ 开销大 |
| 包含函数 / 特殊对象 | ✅ 正常处理 | ❌ JSON 方法会丢失 |
| 循环引用 | ✅ 无影响 | ❌ 需特殊处理 |
建议:
- 优先使用浅拷贝:在无需完全隔离数据时,用
Object.assign()或扩展运算符。 - 谨慎使用深拷贝:仅在必要时使用
lodash.cloneDeep()或手动实现,避免性能问题。 - Vue 响应式数据:使用
Vue.set()或Vuex的clone()工具处理嵌套对象。

1万+

被折叠的 条评论
为什么被折叠?



