【JS】JS基础-浅克隆vs深克隆

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"
  }
};

// 方法1: 展开运算符
const shallowCopy1 = { ...originalObj };

// 方法2: Object.assign()
const shallowCopy2 = Object.assign({}, originalObj);

// 方法3: 数组的浅拷贝
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()) {
  // 处理基本数据类型和null
  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: 使用第三方库(推荐用于生产环境)
// Lodash
const _ = require('lodash');
const deepCopy = _.cloneDeep(originalObj);

// 或者其他工具库如 Ramda, Underscore 等

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); // "Alice" - 未改变
console.log("原始对象hobbies:", original.hobbies); // ["reading", "coding", "gaming"] - 被改变!
console.log("原始对象address.city:", original.address.city); // "Shanghai" - 被改变!

// 深克隆测试
const deepCopy = deepClone(original); // 使用上面的deepClone函数
deepCopy.name = "Charlie";
deepCopy.hobbies.push("swimming");
deepCopy.address.coordinates[0] = 120.0;

console.log("\n深克隆结果:");
console.log("原始对象name:", original.name); // "Alice" - 未改变
console.log("原始对象hobbies:", original.hobbies); // ["reading", "coding", "gaming"] - 未改变!
console.log("原始对象address.coordinates:", original.address.coordinates); // [116.4, 39.9] - 未改变!

5. 各种数据类型的处理对比

数据类型浅克隆效果JSON深克隆效果完整深克隆效果
基本类型✅ 完全复制✅ 完全复制✅ 完全复制
普通对象❌ 共享引用✅ 独立复制✅ 独立复制
数组❌ 共享引用✅ 独立复制✅ 独立复制
函数✅ 复制引用❌ 丢失✅ 复制引用
Date对象✅ 复制引用❌ 变成字符串✅ 正确复制
RegExp✅ 复制引用❌ 变成空对象✅ 正确复制
Map/Set✅ 复制引用❌ 变成空对象✅ 正确复制
循环引用✅ 保持引用❌ 报错✅ 正确处理
Symbol✅ 复制引用❌ 丢失✅ 正确复制
undefined✅ 复制引用❌ 丢失✅ 正确复制

6. 性能考虑

// 性能测试示例
const largeObj = createLargeObject(1000); // 创建一个包含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);

// 简单场景可以使用现代浏览器内置的API
const simpleDeepCopy = structuredClone(originalObject); // 注意浏览器兼容性

8. 现代浏览器解决方案:structuredClone

// HTML5 新增的深克隆API(注意兼容性)
const original = {
  name: "Alice",
  hobbies: ["reading", "coding"],
  date: new Date(),
  set: new Set([1, 2, 3])
};

const cloned = structuredClone(original); // 原生深克隆API

// 支持的数据类型比JSON方法更多,但仍不支持函数

总结

特性浅克隆深克隆
复制深度仅第一层所有层级
引用类型处理共享引用创建新引用
性能低(取决于深度)
内存占用
使用复杂度简单复杂
适用场景简单对象、性能敏感复杂对象、数据隔离

选择哪种克隆方式取决于具体的业务需求、数据结构和性能要求。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

蓝莓味的口香糖

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值