[toc]
深浅拷贝的原理及手写
浅拷贝
1. 核心原理
浅拷贝是指:创建一个新对象,该对象具有原始对象属性值的精确副本
- 基本类型:直接拷贝其值(如数字、字符串)
- 引用类型:拷贝其内存地址。这意味着新旧对象指向同一个堆内存空间,修改其中一个嵌套对象,另一个也会受影响
2. 浅拷贝的多种实现方式
Object.assign()
特点:遍历源对象的可枚举属性,通过赋值方式处理
注意:不拷贝继承属性和不可枚举属性,但支持 Symbol
jslet target = { a: 1 }; let source = { b: { d: 2 } }; Object.assign(target, source); source.b.d = 666; console.log(target.b.d); // 666 (受影响)
扩展运算符 (
...)在构造字面量对象时进行属性拷贝,语法最简洁
jslet obj1 = { a: 1, b: { c: 1 } }; let obj2 = { ...obj1 };数组特有:slice() 与 concat()
slice():返回选定元素的新数组concat():合并数组并返回副本。 两者均不会改变原数组,但对内部的对象依然是浅拷贝引用
3. 手写实现浅拷贝
JavaScript
function shallowCopy(object) {
if (!object || typeof object !== "object") return;
let newObject = Array.isArray(object) ? [] : {};
for (let key in object) {
if (object.hasOwnProperty(key)) {
newObject[key] = object[key];
}
}
return newObject;
}
const original = {a: 1, b: {c: 2}};
const copied = shallowCopy(original);
console.log(copied); // {a: 1, b: {c: 2}}
console.log(original === copied); // false
console.log(original.b === copied.b); // true深拷贝
1. 核心原理
深拷贝会在堆内存中开辟一块全新的内存地址,递归地将原对象的所有层级属性全部拷贝过来。两个对象相互独立,修改任何一级属性都不会影响对方
2. 深拷贝的常见方案
JSON 序列化 (最简便)
JSON.parse(JSON.stringify(obj))- 优点:简单粗暴,解决 90% 的日常纯数据拷贝
- 致命陷阱:无法拷贝函数、
undefined、Symbol、正则对象、循环引用
Lodash 库:
_.cloneDeep在企业级项目中,推荐使用成熟的工具库,其内部处理了极其复杂的边界情况(如 Buffer、TypedArray 等)
3. 手写深拷贝
JavaScript
// 深拷贝
function deepCopy(obj) {
if (obj === null || typeof obj !== 'object') return obj;
const result = Array.isArray(obj) ? [] : {};
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
result[key] = deepCopy(obj[key]);
}
}
return result;
}
const original = {a: 1, b: {c: 2}};
const cloned = deepCopy(original);
console.log(cloned); // { a: 1, b: { c: 2 } }
console.log(original === cloned); // false
console.log(original.b === cloned.b); // false深浅拷贝对比
| 复制层级 | 仅限第一层 | 所有嵌套层级 |
|---|---|---|
| 内存表现 | 引用类型共享堆内存地址 | 引用类型拥有独立的堆空间 |
| 修改原对象 | 嵌套属性修改会同步受影响 | 互不干扰,完全独立 |
| 性能开销 | 极低,速度快 | 相对较高(取决于嵌套深度) |
| 推荐用法 | 简单状态合并(Object.assign) | 复杂业务对象克隆(Lodash) |