深浅拷贝

  1. 浅拷贝 (Shallow Copy)
    只复制对象的表层属性,如果属性值是引用类型(如对象、数组),则拷贝的是引用地址,原对象和拷贝对象会共享这些引用类型的数据。
    常见的浅拷贝方法:
// 1. Object.assign()
const obj1 = { a: 1, b: { c: 2 } };
const copy1 = Object.assign({}, obj1);

// 2. 扩展运算符 ...
const obj2 = { a: 1, b: { c: 2 } };
const copy2 = { ...obj2 };

// 3. 数组浅拷贝
const arr1 = [1, [2, 3]];
const copy3 = arr1.slice();
const copy4 = [...arr1];
  1. 深拷贝 (Deep Copy)
    完全复制对象的所有层级,包括嵌套的引用类型,原对象和拷贝对象相互独立,修改其中一个不会影响另一个。
    常见的深拷贝方法:
// 方法1: JSON序列化(简单场景适用,有局限性)
function deepCopyByJSON(obj) {
  return JSON.parse(JSON.stringify(obj));
}
// 局限性:不能拷贝函数、正则、循环引用等

// 方法2: 递归实现深拷贝(更完善)
function deepCopy(obj, hash = new WeakMap()) {
  // 处理null和基本类型
  if (obj === null || typeof obj !== 'object') return obj;
  
  // 处理日期
  if (obj instanceof Date) return new Date(obj);
  
  // 处理正则
  if (obj instanceof RegExp) return new RegExp(obj.source, obj.flags);
  
  // 处理循环引用
  if (hash.has(obj)) return hash.get(obj);
  
  // 创建新对象/数组
  let cloneObj = Array.isArray(obj) ? [] : {};
  hash.set(obj, cloneObj);
  
  // 递归拷贝属性
  Reflect.ownKeys(obj).forEach(key => {
    cloneObj[key] = deepCopy(obj[key], hash);
  });
  
  return cloneObj;
}

// 使用示例
const original = {
  name: "test",
  age: 20,
  info: {
    address: "city",
    hobbies: ["reading", "coding"]
  },
  date: new Date(),
  regex: /hello/g
};

const deepClone = deepCopy(original);
  1. 深浅拷贝的主要区别
    浅拷贝:只拷贝第一层,嵌套对象共享引用
    深拷贝:拷贝所有层级,嵌套对象完全独立
  2. 使用场景建议
    简单数据结构且无嵌套引用类型:可以使用浅拷贝
    复杂数据结构或有嵌套引用类型:需要使用深拷贝
    注意循环引用问题:自定义递归深拷贝时需处理

应用场景:

  1. 浅拷贝的典型用场景
    浅拷贝适用于 单层数据结构 或 不需要完全隔离嵌套对象 的场景,因为它性能更好(无需递归处理深层结构)。
    (1)简单数据的复制与修改
    当对象 / 数组仅包含基本类型(字符串、数字、布尔等),没有嵌套引用类型时,浅拷贝足够安全。
// 用户信息(无嵌套对象)
const user = { name: "Alice", age: 25, isActive: true };

// 浅拷贝:修改副本不影响原对象
const updatedUser = { ...user };
updatedUser.age = 26;
console.log(user.age); // 25(原对象不变)

(2)状态管理中的部分更新
在 React/Vue 等框架中,更新状态时常用浅拷贝创建新对象,触发视图更新(无需深拷贝整个状态树)。

// React 状态更新(仅修改部分属性)
const [form, setForm] = useState({ username: "", password: "" });

// 浅拷贝现有状态,只更新需要修改的字段
setForm({ ...form, username: "newName" });

(3)数组的简单处理
对数组进行切片、过滤等操作时,浅拷贝可快速创建新数组(适用于数组元素为基本类型的情况)。

const arr = [1, 2, 3, 4];
const filtered = arr.filter(item => item > 2); // 浅拷贝新数组
const sliced = arr.slice(1, 3); // 浅拷贝子数组
  1. 深拷贝的典型用场景
    深拷贝适用于 包含嵌套引用类型 且 需要完全隔离原数据与副本 的场景,避免修改副本时影响原数据。
    (1)复杂数据的备份与编辑
    当数据包含多层嵌套对象 / 数组(如表单配置、树形结构),必须用深拷贝确保原数据不被意外修改。
// 嵌套结构的配置数据
const config = {
  theme: "light",
  settings: {
    notifications: true,
    layout: { columns: 2 }
  }
};

// 深拷贝:完全隔离原数据
const editedConfig = deepCopy(config);
editedConfig.settings.layout.columns = 3;
console.log(config.settings.layout.columns); // 2(原数据不变)

(2)避免循环引用导致的问题
在处理可能包含循环引用的数据(如 DOM 元素引用、双向关联对象)时,需用支持循环引用的深拷贝方法。

const obj = { name: "A" };
obj.self = obj; // 循环引用(obj 引用自身)

// 用支持循环引用的深拷贝函数
const copy = deepCopy(obj); // 不会报错,且能正确复制

(3)缓存与数据快照
需要保存数据的历史状态(如撤销 / 重做功能)时,深拷贝可创建独立的快照,避免历史记录被后续操作污染。

// 保存编辑器历史记录
const history = [];
let currentState = { content: "hello", cursor: { x: 5, y: 10 } };

// 深拷贝当前状态到历史记录
history.push(deepCopy(currentState));

// 修改当前状态后,历史记录不受影响
currentState.content = "world";
console.log(history[0].content); // "hello"

(4)函数参数的安全处理
当函数需要修改传入的对象参数,又不想影响外部原始数据时,深拷贝可隔离参数与原对象。

function processData(data) {
  // 深拷贝参数,避免修改外部数据
  const copied = deepCopy(data);
  copied.details = "processed";
  return copied;
}

const original = { id: 1 };
const result = processData(original);
console.log(original.details); // undefined(原对象未被修改)
  1. 如何选择?
    优先浅拷贝:单层数据、性能敏感场景、仅需部分更新数据。
    必须深拷贝:嵌套数据、需要完全隔离的场景(如备份、历史记录)、包含循环引用。
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容