关于js深拷贝的深究

119 阅读2分钟

以下是一篇关于JavaScript深拷贝的详细文章结构,您可以直接使用或调整:

深入解析JavaScript深拷贝:原理、实现与避坑指南

一、为什么需要深拷贝?

在前端开发中,我们经常遇到对象/数组的复制需求。当直接使用=赋值时,实际上只是复制了引用地址(浅拷贝),导致修改新对象会影响原对象:

const obj = { a: 1, b: { c: 2 } };const shallowCopy = obj;shallowCopy.b.c = 3;console.log(obj.b.c); // 3 原对象被修改!

深拷贝能彻底解决这个问题,创建完全独立的新对象。---## 二、深拷贝常见方案对比### 1. JSON方法(有局限性)

const deepCopy = JSON.parse(JSON.stringify(obj));

缺点:- 无法处理undefinedfunctionSymbol- 忽略原型链- 循环引用会报错- 丢失特殊对象类型(如Date变为字符串)### 2. 第三方库(推荐)

// lodashimport { cloneDeep } from 'lodash';const deepCopy = cloneDeep(obj);

3. 手动实现(本文重点)---## 三、手写深拷贝函数(进阶版)### 基础版本

function deepClone(target) {  if (typeof target !== 'object' || target === null) {    return target; // 基本类型直接返回  }    const cloneTarget = Array.isArray(target) ? [] : {};    for (let key in target) {    if (target.hasOwnProperty(key)) {      cloneTarget[key] = deepClone(target[key]);    }  }    return cloneTarget;}

进阶优化逐步解决以下问题:1. 循环引用问题

function deepClone(target, map = new WeakMap()) {  if (map.has(target)) return map.get(target);  // ...其他逻辑  map.set(target, cloneTarget);  // ...递归拷贝}```2. **特殊对象处理**```javascript// 获取对象的构造函数const constructor = target.constructor;// 处理Dateif (target instanceof Date) {  return new Date(target);}// 处理RegExpif (target instanceof RegExp) {  return new RegExp(target);}// 处理Map/Setif (target instanceof Map) {  const cloneMap = new Map();  target.forEach((value, key) => {    cloneMap.set(key, deepClone(value));  });  return cloneMap;}// Set同理
  1. 函数拷贝(视需求决定是否保留引用)
    javascript if (typeof target === 'function') { return target.bind({}); // 简单处理}

四、现代API方案

1. structuredClone

支持:Array/Object/Date/RegExp/Map/Set等 限制:不支持函数、DOM节点、原型链### 2. MessageChannel

function structuralClone(obj) {  return new Promise(resolve => {    const { port1, port2 } = new MessageChannel();    port2.onmessage = ev => resolve(ev.data);    port1.postMessage(obj);  });}

五、总结

  • 深拷贝的核心是递归遍历+类型判断
  • 生产环境推荐使用成熟的工具库
  • 注意特殊对象类型和循环引用问题
  • 根据业务需求选择合适的拷贝方式