javascript对象拷贝开销本质是内存操作成本:栈值拷贝极快,堆地址拷贝仅指针移动;浅拷贝只新建第一层容器,耗时≈属性数×写内存次数;深拷贝因递归分配堆空间、类型判断与循环引用检测,开销显著更高。

对象拷贝开销,本质是内存操作成本——不是“复制了多少数据”,而是“新建了多少堆空间 + 多少次引用跳转 + 是否触发额外逻辑”。JavaScript 引擎(如 V8)不提供直接的拷贝指令,所有拷贝行为都由运行时代码模拟,因此开销完全取决于你选择的策略在底层如何执行。
栈值拷贝快如闪电,堆地址拷贝只是指针移动
基本类型(number、string、boolean 等)存在栈中,赋值就是 CPU 寄存器级的值复制,毫秒级不可测。而对象变量本身只存一个 8 字节(64 位系统)的堆地址,直接赋值 obj2 = obj1 实际只复制这个地址——零堆分配、无遍历、无递归,开销趋近于零。但这不是“拷贝对象”,只是共享引用。
浅拷贝:新建容器,不碰嵌套数据
像 Object.assign({}, obj) 或展开运算符 {...obj},引擎会:
- 为新对象分配一块堆内存(仅第一层结构)
- 把原对象每个自有属性的「键」和「值」逐个写入新内存
- 若值是基本类型,直接复制值;若值是引用(比如
obj.nested),只复制那个地址
它不访问 nested 指向的那块堆内存,更不会为其分配新空间。所以浅拷贝耗时≈属性数量 × 写内存次数,与嵌套深度无关。
深拷贝:递归触发多次堆分配与类型判断
真正开销来自这里。每次遇到一个引用类型,引擎必须:
- 识别其真实类型(
Array、Date、Map…需调用Object.prototype.toString.call()或getTag()) - 为该类型分配新堆空间(
new Array()、new Date()等构造调用) - 遍历其内容,对每个子项重复上述过程(递归栈帧压入)
- 检测循环引用时,还需维护 WeakMap 缓存表并做哈希查找
例如拷贝一个含 10 层嵌套的树形对象,引擎可能执行上千次堆分配、上万次属性读取+写入,还要承担递归调用栈管理成本。这就是为什么 JSON.parse(JSON.stringify()) 看似简单却慢——它实际经历了序列化(字符串拼接)、解析(语法树重建)、两次内存分配(字符串 + 新对象)三重开销。
现代方案如何降低底层开销?
structuredClone() 和 fast-copy 的优势不在“魔法”,而在绕过低效路径:
-
structuredClone()由引擎原生实现,跳过 JS 层递归,直接在 C++ 层遍历内部描述符,避免 JS 调用栈和类型反射开销 -
fast-copy用类型优先分发(type-first dispatch),提前匹配Array.isArray()、isDate()等快速路径,减少冗余判断;缓存复用已处理对象,避免重复分配
它们没减少堆分配总量,但减少了 JS 层的解释执行、属性枚举、动态类型检查这些“软开销”,这才是性能跃升的关键。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











