1. 基本概念
浅克隆 (Shallow Clone)
- 只复制对象的第一层属性
- 对于引用类型的属性,复制的是引用(内存地址)
- 原始对象和克隆对象共享嵌套的引用类型属性
深克隆 (Deep Clone)
- 递归复制对象的所有层级属性
- 创建完全独立的新对象,不共享任何引用
- 修改克隆对象不会影响原始对象
2. 内存结构对比
浅克隆的内存结构
原始对象: { name: "Alice", hobbies: ↗ }
克隆对象: { name: "Alice", hobbies: ↗ }
↓
["reading", "coding"]
深克隆的内存结构
原始对象: { name: "Alice", hobbies: ↗ } → ["reading", "coding"]
克隆对象: { name: "Alice", hobbies: ↗ } → ["reading", "coding"] (新数组)
3. 实现方式对比
浅克隆的实现方法
const originalObj = {
name: "Alice",
age: 25,
hobbies: ["reading", "coding"],
address: {
city: "Beijing",
street: "Wangfujing"
}
};
const shallowCopy1 = { ...originalObj };
const shallowCopy2 = Object.assign({}, originalObj);
const originalArr = [1, 2, { name: "test" }];
const shallowCopyArr = originalArr.slice();
const shallowCopyArr2 = [...originalArr];
深克隆的实现方法
方法1: JSON方法(最简单但有局限)
const deepCopy = JSON.parse(JSON.stringify(originalObj));
方法2: 手动递归实现(功能完整)
function deepClone(obj, hash = new WeakMap()) {
if (obj === null || typeof obj !== "object") {
return obj;
}
if (obj instanceof Date) {
return new Date(obj.getTime());
}
if (Array.isArray(obj)) {
return obj.map(item => deepClone(item, hash));
}
if (hash.has(obj)) {
return hash.get(obj);
}
const clonedObj = Object.create(Object.getPrototypeOf(obj));
hash.set(obj, clonedObj);
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
clonedObj[key] = deepClone(obj[key], hash);
}
}
return clonedObj;
}
方法3: 使用第三方库(推荐用于生产环境)
const _ = require('lodash');
const deepCopy = _.cloneDeep(originalObj);
4. 详细对比示例
const original = {
name: "Alice",
age: 25,
hobbies: ["reading", "coding"],
address: {
city: "Beijing",
coordinates: [116.4, 39.9]
},
sayHello: function() {
return `Hello, I'm ${this.name}`;
},
birthDate: new Date('1990-01-01')
};
const shallowCopy = { ...original };
shallowCopy.name = "Bob";
shallowCopy.hobbies.push("gaming");
shallowCopy.address.city = "Shanghai";
console.log("浅克隆结果:");
console.log("原始对象name:", original.name);
console.log("原始对象hobbies:", original.hobbies);
console.log("原始对象address.city:", original.address.city);
const deepCopy = deepClone(original);
deepCopy.name = "Charlie";
deepCopy.hobbies.push("swimming");
deepCopy.address.coordinates[0] = 120.0;
console.log("\n深克隆结果:");
console.log("原始对象name:", original.name);
console.log("原始对象hobbies:", original.hobbies);
console.log("原始对象address.coordinates:", original.address.coordinates);
5. 各种数据类型的处理对比
| 数据类型 | 浅克隆效果 | JSON深克隆效果 | 完整深克隆效果 |
|---|
| 基本类型 | ✅ 完全复制 | ✅ 完全复制 | ✅ 完全复制 |
| 普通对象 | ❌ 共享引用 | ✅ 独立复制 | ✅ 独立复制 |
| 数组 | ❌ 共享引用 | ✅ 独立复制 | ✅ 独立复制 |
| 函数 | ✅ 复制引用 | ❌ 丢失 | ✅ 复制引用 |
| Date对象 | ✅ 复制引用 | ❌ 变成字符串 | ✅ 正确复制 |
| RegExp | ✅ 复制引用 | ❌ 变成空对象 | ✅ 正确复制 |
| Map/Set | ✅ 复制引用 | ❌ 变成空对象 | ✅ 正确复制 |
| 循环引用 | ✅ 保持引用 | ❌ 报错 | ✅ 正确处理 |
| Symbol | ✅ 复制引用 | ❌ 丢失 | ✅ 正确复制 |
| undefined | ✅ 复制引用 | ❌ 丢失 | ✅ 正确复制 |
6. 性能考虑
const largeObj = createLargeObject(1000);
console.time('浅克隆');
const shallow = { ...largeObj };
console.timeEnd('浅克隆');
console.time('JSON深克隆');
const jsonDeep = JSON.parse(JSON.stringify(largeObj));
console.timeEnd('JSON深克隆');
console.time('递归深克隆');
const recursiveDeep = deepClone(largeObj);
console.timeEnd('递归深克隆');
7. 使用建议
使用浅克隆的场景:
- 对象只有一层结构,没有嵌套引用类型
- 性能要求极高,且确定不会修改嵌套属性
- 确实需要共享某些属性的引用
使用深克隆的场景:
- 对象有复杂的嵌套结构
- 需要完全独立的对象副本
- 需要修改嵌套属性而不影响原对象
- 函数参数传递时避免副作用
最佳实践:
import { cloneDeep } from 'lodash';
const safeDeepCopy = cloneDeep(originalObject);
const simpleDeepCopy = structuredClone(originalObject);
8. 现代浏览器解决方案:structuredClone
const original = {
name: "Alice",
hobbies: ["reading", "coding"],
date: new Date(),
set: new Set([1, 2, 3])
};
const cloned = structuredClone(original);
总结
| 特性 | 浅克隆 | 深克隆 |
|---|
| 复制深度 | 仅第一层 | 所有层级 |
| 引用类型处理 | 共享引用 | 创建新引用 |
| 性能 | 高 | 低(取决于深度) |
| 内存占用 | 低 | 高 |
| 使用复杂度 | 简单 | 复杂 |
| 适用场景 | 简单对象、性能敏感 | 复杂对象、数据隔离 |
选择哪种克隆方式取决于具体的业务需求、数据结构和性能要求。