You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在JavaScript中实现可靠的嵌套对象深度克隆函数?

寻找JavaScript中可靠的深度克隆方案

我需要一个能完整克隆对象(包括所有嵌套属性和数组)的深度克隆函数。试过JSON.parse(JSON.stringify(obj)),但它存在诸多局限(比如无法处理函数、循环引用、特殊对象类型),而且我自己写的递归函数也没达到预期效果——修改克隆后的对象或其嵌套属性会影响原对象。

我的递归实现代码:

function deepClone(obj) {
  if (typeof obj !== 'object' || obj === null) {
    return obj;
  }
  
  let clone = Array.isArray(obj) ? [] : {};
  
  for (let key in obj) {
    if (obj.hasOwnProperty(key)) {
      clone[key] = deepClone(obj[key]);
    }
  }
  
  return clone;
}

// 使用示例:
let originalObj = {
  name: 'John',
  age: 30,
  address: {
    street: '123 Main St',
    city: 'New York',
    state: 'NY'
  },
  hobbies: ['reading', 'cooking', 'swimming']
};

let clonedObj = deepClone(originalObj);

改进版深度克隆实现

你的递归代码在处理普通嵌套对象/数组时理论上是有效的,出现修改克隆体影响原对象的情况,大概率是原对象包含了循环引用、特殊类型(如Date、RegExp),或是测试操作有误。以下是覆盖更多场景的稳健实现:

function deepClone(obj, visited = new WeakMap()) {
  // 处理基本类型与null
  if (obj === null || typeof obj !== 'object') {
    return obj;
  }

  // 处理循环引用,避免无限递归
  if (visited.has(obj)) {
    return visited.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 Map) {
    const cloneMap = new Map();
    visited.set(obj, cloneMap);
    obj.forEach((value, key) => {
      cloneMap.set(deepClone(key, visited), deepClone(value, visited));
    });
    return cloneMap;
  }

  if (obj instanceof Set) {
    const cloneSet = new Set();
    visited.set(obj, cloneSet);
    obj.forEach(value => {
      cloneSet.add(deepClone(value, visited));
    });
    return cloneSet;
  }

  // 保留原对象的原型链
  const clone = Array.isArray(obj) ? [] : Object.create(Object.getPrototypeOf(obj));
  visited.set(obj, clone);

  // 遍历所有自有属性(含不可枚举属性)
  Object.getOwnPropertyNames(obj).forEach(key => {
    clone[key] = deepClone(obj[key], visited);
  });

  // 处理Symbol类型的属性
  Object.getOwnPropertySymbols(obj).forEach(sym => {
    clone[sym] = deepClone(obj[sym], visited);
  });

  return clone;
}

核心优势

  • 解决循环引用:通过WeakMap记录已克隆对象,避免无限递归和引用混乱
  • 支持特殊对象类型:正确克隆Date、RegExp、Map、Set等内置对象
  • 保留原型链:克隆对象继承原对象的原型结构
  • 覆盖全量属性:包括不可枚举属性和Symbol类型属性

验证测试

用复杂对象测试克隆效果:

let originalObj = {
  name: 'John',
  age: 30,
  address: {
    street: '123 Main St',
    city: 'New York',
    state: 'NY'
  },
  hobbies: ['reading', 'cooking', 'swimming'],
  birthDate: new Date('1993-01-01'),
  regex: /test/i,
  map: new Map([['key1', 'value1']]),
  set: new Set([1, 2, 3])
};

let clonedObj = deepClone(originalObj);

// 修改克隆对象的嵌套属性
clonedObj.address.street = '456 Oak Ave';
clonedObj.hobbies.push('hiking');
clonedObj.birthDate.setFullYear(1994);

console.log(originalObj.address.street); // 输出 '123 Main St',原对象未被修改
console.log(originalObj.hobbies); // 输出 ['reading', 'cooking', 'swimming'],原数组未被修改
console.log(originalObj.birthDate.getFullYear()); // 输出 1993,原日期未被修改

如果你的原代码出现异常,建议检查:

  1. 是否在测试时误操作了原对象
  2. 原对象是否包含循环引用或特殊类型(原代码未处理这些场景)

内容的提问来源于stack exchange,提问作者Haitham6373

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 14:57:36