浅拷贝 vs 深拷贝

对比浅拷贝和深拷贝的引用层级差异,以及面试中常问的使用边界。

#type / concept #status / growing #tech / dev / frontend

浅拷贝 vs 深拷贝

一句话定义

浅拷贝只复制对象的第一层属性,嵌套对象仍是共享引用;深拷贝递归复制所有层级,产出完全独立的副本。

核心机制:引用 vs 值

JavaScript 中对象是引用类型。赋值 const b = a 只是让 b 指向同一块内存,不产生新对象。

赋值:       a ──→ { x: 1, inner: { y: 2 } } ←── b   (同一对象)

浅拷贝:     a ──→ { x: 1, inner: ──┐ }
                                    └→ { y: 2 } ←── b.inner   (共享)
            b ──→ { x: 1, inner: ──┘ }

深拷贝:     a ──→ { x: 1, inner: { y: 2 } }      (独立)
            b ──→ { x: 1, inner: { y: 2 } }      (独立)

浅拷贝方法

const original = { name: 'Alice', scores: [90, 85] };

// 1. Object.assign
const clone1 = Object.assign({}, original);

// 2. 展开运算符
const clone2 = { ...original };

// 3. Array.slice / Array.from(数组)
const arr = [1, [2, 3]];
const arrClone = arr.slice();
// 或
const arrClone2 = [...arr];

证明是浅拷贝

clone1.scores.push(100);
console.log(original.scores); // [90, 85, 100] — 被影响了!

深拷贝方法

// 1. structuredClone(推荐)
const deep1 = structuredClone(original);

// 2. JSON(有限制)
const deep2 = JSON.parse(JSON.stringify(original));

// 3. 手写递归 / lodash _.cloneDeep

嵌套突变示例:为什么它重要

const state = {
  user: { name: 'Alice', address: { city: 'Beijing' } },
  items: [1, 2, 3]
};

// 浅拷贝更新(Redux-style 错误示范)
const newState = { ...state };
newState.user.name = 'Bob';
console.log(state.user.name); // "Bob" — 原 state 被污染了!

// 正确做法:逐层深拷贝
const correctState = {
  ...state,
  user: { ...state.user, address: { ...state.user.address } },
  items: [...state.items]
};

选择建议

场景推荐
对象只有一层(扁平)浅拷贝({ ...obj }
需要修改嵌套结构深拷贝或不可变更新(Immer)
Redux / 状态管理不可变更新(只拷贝变更路径)
数据传输 / 快照structuredClone

边界与常见误解

  • 展开运算符 { ...obj } 不是深拷贝:这是最常见的误解,它只是浅拷贝。
  • 浅拷贝够用的条件:当你只操作顶层属性、或使用不可变数据流(每次替换整个子对象)时。
  • 性能:深拷贝有递归开销,数据量大时优先考虑结构共享(如 Immer 的 Copy-on-Write)。
创建于 2026/4/9 更新于 2026/5/27