js实现深拷贝和浅拷贝

1. 浅拷贝 vs 深拷贝

  • 浅拷贝

    • 只复制对象的第一层属性。如果属性值是基本类型(如数字、字符串),则复制值;如果属性值是引用类型(如对象、数组),则复制引用地址,修改新对象的引用类型属性会影响原对象。
    • 特点:只复制一层,嵌套对象仍共享引用。
  • 深拷贝

    • 完全复制对象及其所有嵌套层级的属性,生成独立的新对象。修改新对象不会影响原对象。
    • 特点:递归复制所有层级,内存占用较高。

2. 浅拷贝的实现方法

以下是几种常见的浅拷贝实现方法:

方法1:Object.assign()
  • 复制对象的第一层属性。
const obj = { a: 1, b: { c: 2 } };
const shallowCopy = Object.assign({}, obj);

// 测试
shallowCopy.a = 10; // 不影响原对象
shallowCopy.b.c = 20; // 影响原对象的b.c
console.log(obj); // { a: 1, b: { c: 20 } }
console.log(shallowCopy); // { a: 10, b: { c: 20 } }
方法2:展开运算符(…)
  • 适用于对象和数组,复制第一层。
const arr = [1, [2, 3]];
const shallowCopy = [...arr];

// 测试
shallowCopy[0] = 10; // 不影响原数组
shallowCopy[1][0] = 20; // 影响原数组的[2, 3]
console.log(arr); // [1, [20, 3]]
console.log(shallowCopy); // [10, [20, 3]]
方法3:Array.slice()
  • 仅适用于数组,复制第一层。
const arr = [1, [2, 3]];
const shallowCopy = arr.slice();

// 测试
shallowCopy[0] = 10; // 不影响原数组
shallowCopy[1][0] = 20; // 影响原数组
console.log(arr); // [1, [20, 3]]
console.log(shallowCopy); // [10, [20, 3]]

3. 深拷贝的实现方法

深拷贝需要递归处理嵌套对象,以下是几种实现方法:

方法1:JSON.parse(JSON.stringify())
  • 简单但有局限性(无法处理函数、Date、RegExp、undefined等)。
const obj = { a: 1, b: { c: 2 }, d: [1, 2] };
const deepCopy = JSON.parse(JSON.stringify(obj));

// 测试
deepCopy.b.c = 20;
deepCopy.d[0] = 10;
console.log(obj); // { a: 1, b: { c: 2 }, d: [1, 2] }
console.log(deepCopy); // { a: 1, b: { c: 20 }, d: [10, 2] }

局限性

  • 无法复制函数:{ fn: () => {} } -> { fn: null }
  • Date对象变为字符串:{ date: new Date() } -> { date: "2025-11-06T..." }
  • 忽略undefined和Symbol。
方法2:递归实现深拷贝
  • 手动实现,处理复杂数据类型。
function deepCopy(obj, cache = new WeakMap()) {
  // 处理基本类型和null
  if (obj === null || typeof obj !== 'object') return obj;

  // 处理循环引用
  if (cache.has(obj)) return cache.get(obj);

  // 处理数组
  if (Array.isArray(obj)) {
    const copy = [];
    cache.set(obj, copy);
    obj.forEach((item, i) => {
      copy[i] = deepCopy(item, cache);
    });
    return copy;
  }

  // 处理对象
  const copy = {};
  cache.set(obj, copy);
  Object.keys(obj).forEach(key => {
    copy[key] = deepCopy(obj[key], cache);
  });

  return copy;
}

// 测试
const obj = { a: 1, b: { c: 2 }, d: [1, 2] };
obj.circular = obj; // 循环引用
const copy = deepCopy(obj);
copy.b.c = 20;
copy.d[0] = 10;
console.log(obj); // { a: 1, b: { c: 2 }, d: [1, 2], circular: [Circular] }
console.log(copy); // { a: 1, b: { c: 20 }, d: [10, 2], circular: [Circular] }

特点

  • 支持循环引用(通过WeakMap)。
  • 可扩展以处理特殊类型(如Date、RegExp)。
方法3:结构化克隆(structuredClone)
  • 现代浏览器支持的原生API,处理大多数复杂类型。
const obj = { a: 1, b: { c: 2 }, d: new Date() };
const deepCopy = structuredClone(obj);

// 测试
deepCopy.b.c = 20;
console.log(obj); // { a: 1, b: { c: 2 }, d: Date }
console.log(deepCopy); // { a: 1, b: { c: 20 }, d: Date }

局限性

  • 浏览器环境独有,Node.js需18.0+版本。
  • 不支持函数和某些特殊对象。
方法4:第三方库(如Lodash)
  • 使用_.cloneDeep实现深拷贝。
const _ = require('lodash');
const obj = { a: 1, b: { c: 2 }, fn: () => {} };
const deepCopy = _.cloneDeep(obj);

// 测试
deepCopy.b.c = 20;
console.log(obj); // { a: 1, b: { c: 2 }, fn: [Function] }
console.log(deepCopy); // { a: 1, b: { c: 20 }, fn: [Function] }

4. 深拷贝与浅拷贝的示例场景

浅拷贝场景
  • 场景1:简单对象复制
    • 复制表单数据,仅修改第一层属性(如{ name: "Alice", age: 25 })。
    • 方法:Object.assign()...
  • 场景2:数组操作
    • 复制数组进行排序或过滤,但不修改嵌套对象。
    • 方法:[...arr]arr.slice()
  • 场景3:React状态更新
    • 更新React state时,复制state对象的第一层,避免直接修改原state。
    • 示例:setState({ ...state, count: state.count + 1 })
深拷贝场景
  • 场景1:复杂对象修改
    • 复制一个嵌套对象(如配置对象),需要独立修改嵌套属性。
    • 方法:deepCopystructuredClone
  • 场景2:状态管理
    • 在Redux或Vuex中,复制store状态以避免直接修改,确保不可变性。
    • 方法:_.cloneDeep或自定义深拷贝。
  • 场景3:数据备份
    • 保存初始数据副本,允许后续修改而不影响原始数据(如编辑器的“撤销”功能)。
    • 方法:JSON.parse(JSON.stringify())(简单场景)或deepCopy

5. 注意事项与面试要点

  • 浅拷贝局限
    • 只适合第一层为基本类型的对象。
    • 常用于性能要求高的场景,因开销小。
  • 深拷贝挑战
    • 处理循环引用、特殊类型(如Date、RegExp)。
    • 性能开销较大,需权衡使用场景。
  • 面试常见问题
    • Q:深拷贝和浅拷贝的区别?
      A:浅拷贝只复制第一层,嵌套对象共享引用;深拷贝递归复制所有层级,新对象完全独立。
    • Q:如何处理循环引用?
      A:使用WeakMap记录已复制对象,避免无限递归。
    • Q:JSON.stringify的局限性?
      A:无法处理函数、undefined、Symbol、循环引用,Date对象转为字符串。
评论 3
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值