96SEO 2026-04-28 07:23 5
在前端的日常编码里“复制对象”这件事kan似轻描淡写,却暗藏无数坑。一次不小心的浅拷贝,就可Neng让页面状态被意外篡改;一次遗漏的循环引用,又会把浏览器逼进死循环。别急,这篇文章会把「浅」和「深」的差别讲得透彻,还会配上几段可直接搬进项目的代码,让你在实际开发中少走弯路。

Ru果把 JavaScript 的内存比作两层抽屉:上层是栈,下层是堆。当我们把一个对象赋给另一个变量时真正搬走的是指针——两个变量指向同一块堆内存。
这也正是「浅拷贝」和「深拷贝」产生分歧的根源:
基本类型在复制时总是值传递,没有所谓的「深」或「浅」。
引用类型则需要决定是只复制指针还是递归复制每一层数据。
二、什么叫「浅拷贝」?它到底Neng干啥?不Neng干啥?说白了就是只把第一层属性搬过去。
常见实现方式
// 展开运算符
const copy1 = { ...origin };
// Object.assign
const copy2 = Object.assign;
这两招对普通对象和数组douNeng跑通,但碰到以下情况就会尴尬:
Date / RegExp / Map / Set 等内部槽数据没有被枚举出来。
函数属性仍然保持原始引用。
嵌套对象仍然共享同一块堆内存。
手写一个geng靠谱的浅克隆函数
/**
* 只复制第一层属性,同时保留特殊对象的原始构造。
*/
const shallowClone = target => {
// 基本类型或 null 直接返回
if return target;
// 函数保持原样
if return target;
// 日期
if return new Date;
// 正则表达式
if return new RegExp;
// Map
if {
const m = new Map;
target.forEach => m.set);
return m;
}
// Set
if {
const s = new Set;
target.forEach);
return s;
}
// 数组使用展开运算符即可
if ) return ;
// 普通对象:保留原型链
return Object.assign(
Object.create),
target
);
};
上面的实现Yi经Neng满足大多数业务需求——尤其是要保持原型链时它比单纯的 {...obj} geng稳妥。
三、走进「深拷贝」:真正意义上的独立副本深拷贝意味着每一层的数据dou要重新创建。换句话说你对克隆出来的对象Zuo任何修改,dou不会波及到源对象。下面先从Zui简化版本聊起,再逐步升级到完整方案。
1️⃣ 简易版:仅支持 JSON Neng序列化的数据结构
// 只适用于不含函数、Symbol、Date 等特殊值的数据
const simpleDeepClone = obj => JSON.parse);
这种写法极简,却有致命缺陷:
2️⃣ 手写递归版:覆盖数组 & 普通对象,同时处理 Symbol 属性
这段代码Yi经Ke以应付大部分业务场景,只要你的对象里没有自指向或者特殊内建实例,就Neng安全运行。 为什么要提前把 通过上述实验,你Ke以直观感受到:
S**shallow** 克隆只Neng隔离第一层属性;二层及以后仍然共享。 S**imple** 深克隆虽然kan起来“一键搞定”,但实际上会把hen多重要信息抹掉。 C**omplete** 深克隆才是真正意义上的“彻底”。它既保留了特殊实例,又解决了循环引用,让你的业务数据在任何场景下dou安全无虞。Date → "{}",
/**
* 递归遍历,实现基本的深克隆。
* 注意:不处理循环引用,也不专门处理 Date/RegExp/Map/Set。
*/
const deepCloneBase = source => {
// 基本类型直接返回
if return source;
// 根据源数据类型创建对应容器
const result = Array.isArray ? : {};
// 合并字符串键与 Symbol 键,确保全部属性被遍历
const keys = ;
for {
result = deepCloneBase;
}
return result;
};
/**
* 完整深克隆实现
* - 支持 Date / RegExp / Map / Set / Symbol 属性
* - 自动检测并缓存Yi遍历过的对象,以防止无限递归
*/
const deepCloneFull = ) => {
// 基础类型直接返回
if return source;
// Yi经克隆过的对象直接复用缓存中的副本
if ) return cache.get;
// 处理特殊构造函数
const ctor = source.constructor;
let clone;
if clone = new Date;
else if clone = new RegExp;
else if {
clone = new Map;
cache.set; // 提前写入缓存以防止自环结构报错
source.forEach => {
clone.set, deepCloneFull);
});
return clone;
}
else if {
clone = new Set;
cache.set;
source.forEach));
return clone;
}
else if ) clone = ;
else {
// 普通对象:保留原型链
clone = Object.create);
}
// 将当前源对象与新建副本关联进缓存表中
cache.set;
// 同时遍历字符串键和 Symbol 键
const props = ;
for {
clone = deepCloneFull;
}
return clone;
};
{source → clone} 写入缓存?
因为Ru果源对象内部出现自指向(例如 {a: obj}),递归进入子属性时会
遇到同一个实例。Ru果不先登记,就会陷入无限递归导致栈溢出。
// 原始数据包含多种特殊结构以及自环引用
const origin = {
name: '小明',
age: 28,
born: new Date,
pattern: /abc/gi,
map: new Map,
set: new Set,
nested: { arr: },
};
// 自环引用测试
origin.self = origin;
// 分别使用三种克隆方法得到副本
const shallowCopy = shallowClone;
const simpleDeepCopy = simpleDeepClone ? simpleDeepClone : null; // 若未定义则为 null
const fullDeepCopy = deepCloneFull;
// 检查关键点 -------------------------------------------------
console.log;
console.log; // true —— 共用同一份实例
console.log;
if{
console.log; // false —— Yi经变成字符串或丢失了
}
console.log;
console.log; // true —— 新建了 Map 实例
console.log; // true —— 循环引用被完整保留
// 改动副本验证互不影响 ------------------------------------
fullDeepCopy.nested.arr.id = 999;
fullDeepCopy.map.set;
console.log; // 原始仍是 1,不受影响
console.log.x); // 原始仍是 1,不受影响
// 输出结果帮助调试 -----------------------------------------
console.dir;
console.dir;
| # | Pitfall | Avoidance |
|---|---|---|
| ① | Date、RegExp 等内部槽不被展开运算符捕获 | 手写针对性处理或使用完整深克隆 |
| ② | 会丢失 undefined 与 Symbol | 不要依赖 JSON 方法进行全局复制 |
| ③ | Circular reference 导致栈溢出 利用 WeakMap / Map 缓存Yi遍历节点||
| ④ | 函数 被错误地当作普通值复制 若无需重新创建,可直接返回原函数实例||
| ⑤ | Merged prototype chain 导致行为差异 普通对象使用 Object.create 保持原型链;数组则保持 Array 实例||
The End 并不是终点,而是你在项目里正式部署安全克隆逻辑的时候。从今天起,你Ke以:
A)快速使用 shallowClone* 在需要轻量级复制且确定不会修改子属性的时候;
B)在大多数业务场景中直接调用 C)Ru果只是想省点性Neng,又确信数据结构hen单薄,可选用简易版 + 手动补齐特殊字段。deepCloneFull* 来获得无死角的数据隔离;
温馨提示:别忘了给你的工具函数加上单元测试!尤其是涉及循环引用和 ES6 容器时一行测试代码往往Neng帮你提前捕获潜在崩溃点。
©2026 前端技术部 | 本文采用 CC BY‑NC‑SA 协议发布,仅供学习交流,如需商业转载请联系作者。作为专业的SEO优化服务提供商,我们致力于通过科学、系统的搜索引擎优化策略,帮助企业在百度、Google等搜索引擎中获得更高的排名和流量。我们的服务涵盖网站结构优化、内容优化、技术SEO和链接建设等多个维度。
| 服务项目 | 基础套餐 | 标准套餐 | 高级定制 |
|---|---|---|---|
| 关键词优化数量 | 10-20个核心词 | 30-50个核心词+长尾词 | 80-150个全方位覆盖 |
| 内容优化 | 基础页面优化 | 全站内容优化+每月5篇原创 | 个性化内容策略+每月15篇原创 |
| 技术SEO | 基本技术检查 | 全面技术优化+移动适配 | 深度技术重构+性能优化 |
| 外链建设 | 每月5-10条 | 每月20-30条高质量外链 | 每月50+条多渠道外链 |
| 数据报告 | 月度基础报告 | 双周详细报告+分析 | 每周深度报告+策略调整 |
| 效果保障 | 3-6个月见效 | 2-4个月见效 | 1-3个月快速见效 |
我们的SEO优化服务遵循科学严谨的流程,确保每一步都基于数据分析和行业最佳实践:
全面检测网站技术问题、内容质量、竞争对手情况,制定个性化优化方案。
基于用户搜索意图和商业目标,制定全面的关键词矩阵和布局策略。
解决网站技术问题,优化网站结构,提升页面速度和移动端体验。
创作高质量原创内容,优化现有页面,建立内容更新机制。
获取高质量外部链接,建立品牌在线影响力,提升网站权威度。
持续监控排名、流量和转化数据,根据效果调整优化策略。
基于我们服务的客户数据统计,平均优化效果如下:
我们坚信,真正的SEO优化不仅仅是追求排名,而是通过提供优质内容、优化用户体验、建立网站权威,最终实现可持续的业务增长。我们的目标是与客户建立长期合作关系,共同成长。
Demand feedback