浅拷贝和深拷贝

发布于:2025-08-02 ⋅ 阅读:(18) ⋅ 点赞:(0)

一、定义

  1. 浅拷贝(Shallow Copy)

    • 拷贝的是对象的第一层属性值:

      • 如果属性是基本类型,直接拷贝值;

      • 如果属性是引用类型(如对象、数组、函数),拷贝的是引用地址,并不会复制内容。

    • 结果:原始对象和新对象共享引用类型属性。

  2. 深拷贝(Deep Copy)

    • 递归地拷贝对象的所有层级属性:

      • 不论是基本类型还是引用类型,

      • 最终生成的对象是完全独立的副本,与原对象没有任何共享。

    • 结果:原始对象和新对象完全独立,互不影响。

二、实现方式

1. 浅拷贝实现方式

方法一:Object.assign()

const obj = { a: 1, b: { c: 2 } };
const shallowCopy = Object.assign({}, obj);

方法二:展开运算符(spread syntax)

const shallowCopy = { ...obj };

方法三:数组用 slice() 或 concat()

const arr = [1, 2, 3];
const newArr = arr.slice(); // 或 arr.concat();

注意:这些方法只复制一层,嵌套对象仍然是引用。

2. 深拷贝实现方式

方法一:JSON.parse(JSON.stringify(obj))【简单、常见】

const deepCopy = JSON.parse(JSON.stringify(obj));
  • 优点:简单直接。

  • 缺点:

    • 会忽略 undefined、function、symbol。

    • 无法处理 Date、RegExp、Map、Set 等特殊类型。

    • 会丢失原型链。

方法二:递归实现

function deepClone(obj, map = new WeakMap()) {
  // 原始类型直接返回(包括 BigInt、Symbol、null、undefined、string 等)
  if (obj === null || typeof obj !== 'object') return obj;

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

  // 特殊类型处理
  if (obj instanceof Date) return new Date(obj.getTime());
  if (obj instanceof RegExp) return new RegExp(obj.source, obj.flags);
  if (obj instanceof Error) {
    const copy = new obj.constructor(obj.message);
    copy.stack = obj.stack;
    return copy;
  }

  // 函数不拷贝,直接返回原始引用(你也可以选择抛错或深克隆 Function)
  if (typeof obj === 'function') return obj;

  // 保留原型
  const result = Array.isArray(obj)
    ? []
    : Object.create(Object.getPrototypeOf(obj));

  // 保存到 WeakMap,处理循环引用
  map.set(obj, result);

  // 拷贝所有属性(包括 Symbol 和不可枚举)
  Reflect.ownKeys(obj).forEach((key) => {
    const desc = Object.getOwnPropertyDescriptor(obj, key);
    if (desc && 'value' in desc) {
      desc.value = deepClone(obj[key], map);
    }
    Object.defineProperty(result, key, desc);
  });

  return result;
}

方法三:使用 Lodash 的 cloneDeep

npm install lodash
import cloneDeep from 'lodash/cloneDeep';

const deepCopy = cloneDeep(obj);
  • 最稳定,支持各种边界情况。

三、实际应用场景

浅拷贝使用场景

  • 只操作对象的第一层结构时:
const state = { count: 1 };
const newState = { ...state, count: 2 };
  • React/Vue中设置状态或props更新时,常用于不可变数据操作。

深拷贝使用场景

  • 需要完全隔离副本,防止引用污染:

    • Redux 状态管理中做 immutable 数据更新;

    • 配置数据模板复制;

    • 表单的“还原为初始值”操作;

    • 克隆嵌套数据结构(如嵌套对象或数组);

四、图示理解

const original = {
  name: "小明",
  info: { age: 26 }
};

const shallow = { ...original };
shallow.info.age = 30;

console.log(original.info.age); // 💥 30(引用被共享)

const deep = JSON.parse(JSON.stringify(original));
deep.info.age = 40;

console.log(original.info.age); // ✅ 30(深拷贝后独立)

五、总结对比表格

特性 浅拷贝 深拷贝
是否递归
引用类型共享 是(只拷贝引用) 否(完全复制)
实现难度 简单 相对复杂
性能 慢(尤其大数据结构)
适用场景 扁平数据结构 嵌套结构、需要独立副本时

网站公告

今日签到

点亮在社区的每一天
去签到