浅拷贝是复制对象顶层属性的地址值而非数据本身,导致新旧对象共享嵌套引用;它实现顶层独立但深层共享,适用于扁平配置合并等场景,不适用于需完全隔离嵌套状态的情形。

浅拷贝在函数传参中看似“按值传递”,实则传递的是引用地址的副本——这个说法容易引发误解,关键在于厘清“值”在这里指什么。
所谓“值”,指的是栈中存储的地址,不是堆中实际数据
JavaScript 和 Python 等语言中,当一个对象(如数组、字典、自定义类实例)作为参数传入函数时,函数接收到的并不是对象本身,而是该对象在堆内存中的地址——这个地址本身是一个基本类型的值(比如 0x7f8a…),存于栈中。传参动作复制了这个地址值,属于“按值传递”,但这个“值”指向的是同一块堆内存。
- 传参过程不复制对象内容,只复制地址(即“指针值”)
- 函数内对对象属性/元素的修改,作用于原堆内存,因此外部可见
- 但如果在函数内把参数重新赋值(如 obj = {}),只是改变了局部变量持有的地址,不影响外部变量
浅拷贝是手动制造一次“地址副本”,而非真正隔离数据
调用 Object.assign({}, obj) 或 list.copy(),本质是新建一个容器(新对象/新列表),再把原对象顶层属性的“值”逐个复制过去。对基本类型属性,复制的是真实数值;对引用类型属性(如嵌套对象、子数组),复制的仍是那个地址——于是新旧对象在深层仍共享同一份数据。
- 浅拷贝后,两个对象的顶层内存地址不同(obj !== copiedObj)
- 但若 obj.nested 是个对象,copiedObj.nested === obj.nested 仍为 true
- 因此修改 copiedObj.nested.field,会同步反映在 obj.nested.field
它不是真正的“值传递”,而是“地址值的值传递”
术语上说“按值传递”没错,但这个“值”是引用地址,不是数据本体。这导致行为上接近“按引用传递”:外部对象可被函数内操作间接修改。浅拷贝正是利用了这一机制,在保留顶层独立性的前提下,复用底层引用以节省内存和性能。
- 它规避了直接赋值(let b = a)带来的完全共享
- 又未达到深拷贝所需的递归遍历与内存开销
- 是一种折中策略:控制变更影响范围至顶层,不穿透嵌套结构
典型误判场景:以为“复制了对象”就等于“隔离了数据”
开发者常因 JSON.parse(JSON.stringify(obj)) 或 structuredClone() 能切断嵌套引用,反推认为 Object.assign 也应如此。实际上,浅拷贝明确不处理嵌套层级——它的设计目的从来不是数据隔离,而是快速生成结构一致的新容器,用于临时操作或配置合并等场景。
- 适合场景:扁平配置对象合并、表单初始值快照、避免直接污染原始 props
- 不适合场景:需要冻结嵌套状态、多层表单联动、不可变数据流(如 Redux 中的状态更新)
- 判断依据:检查修改嵌套属性是否波及原对象,即可验证是否为浅拷贝

















