前提提要:
最近在开发需求时,突然遇到一个问题,我请求过来的数据,怎么还会改变呢??导致卡壳卡了许久,看完才发现,原来是你小子!!深浅拷贝。
既然哥们踩雷了,那不行,得让兄弟们有福同享。
Javascript的数据类型分为:
基本数据类型(值拷贝):
String
, Number
, Boolean
, null
, undefined
, Symbol
, BigInt
特点:直接存储在栈内存,赋值时创建新值
let a = 10;
let b = a; // 创建新值
b = 20;
console.log(a); // 10 (不受影响)
引用数据类型(指针拷贝):
Object
, Array
, Function
, Date
, 等
特点:数据在堆内存,变量存储的是内存地址指针
let obj1 = { name: "John" };
let obj2 = obj1; // 复制指针(指向同一内存)
obj2.name = "Mike";
console.log(obj1.name); // "Mike" (原数据被修改)
首先深浅拷贝是针对引用数据类型的。
只复制对象的第一层属性,嵌套对象仍共享内存地址
实现方式:
...
const source = { a: 1, b: { c: 2 } };
const copy = { ...source };
copy.b.c = 3; // 修改嵌套属性
console.log(source.b.c); // 3 (原对象被修改)
//注意
copy.b.a = 2
console.log(source.a) //1 (未被修改)
可以看到 使用...运算符时,如果第一层数据是基础数据类型 ,是不会被修改的,所以如果属性都是基本类型的值,使用扩展运算符进行拷贝会更加方便。
Object.assign()
const copy = Object.assign({}, source);
const arr = [1, { name: "test" }];
const copy1 = arr.slice();
copy1[1].name = "a"
console.log(arr[1].name) // a
完全克隆对象及其嵌套对象,新旧对象完全隔离
实现方式:
JSON.parse(JSON.stringify())
缺陷:
丢失 undefined
/Symbol
/函数
忽略原型链
循环引用报错
无法处理特殊对象(Date
变字符串、RegExp
变空对象等)
const source = { date: new Date(), fn: () => {} };
const copy = JSON.parse(JSON.stringify(source));
console.log(copy); // { date: "2023-05-15T02:...", fn 丢失 }
function deepClone(source) {
if (source === null || typeof source !== 'object') {
return source;
}
const target = Array.isArray(source) ? [] : {};
for (let key in source) {
if (source.hasOwnProperty(key)) {
target[key] = deepClone(source[key]);
}
}
return target;
}
场景 | 推荐方式 |
---|---|
无嵌套对象/数组 | 浅拷贝 (... /Object.assign() ) |
需要完全隔离的复杂对象 | 完整版深拷贝 |
包含函数/Symbol/特殊对象 | 递归+特殊类型处理 |
超大数据结构 | BFS 迭代深拷贝 |
简单数据快速克隆 | JSON.parse(JSON.stringify()) (需知缺陷) |
一个很基础,但是容易忽视的问题
//定义数据
const arr = [
{
check:true,
name:"YL有搞头"
},
{
check:true,
name:"YL"
},
{
check:true,
name:"有搞头"
}]
//将arr[i]直接push进另一个数组
const newArr = []
newArr.push(arr[0])
//修改newArr的值
newArr[0].check = false
//导致arr的数据遭到修改
arr[0].check = false
//解决办法
newArr.push({...arr[0]})
基本类型:直接复制值,无深浅拷贝概念
浅拷贝:仅复制第一层,嵌套对象共享内存
深拷贝核心难点:
循环引用检测(WeakMap)
特殊对象处理(Date/RegExp/Set/Map)
Symbol 属性复制
原型链维护
性能优化:大数据结构建议使用 BFS 迭代
生产环境:优先使用成熟的库(Lodash 的 _.cloneDeep
)