这是我参与「第五届青训营 」伴学笔记创作活动的第 4 天
Javascript的深浅拷贝
什么是拷贝?
首先在Javascript语言中,对数据分成了七种:
Number,String,undefined,null,Bool,Symbol和Object。
我们将上面这些数据在造出一份一模一样数据的过程就叫拷贝。
数据在内存中是如何存储的?
我们再把上面的七种简单分成两大类,基础数据类型(前六种)和复杂数据类型(Object)。
我们区分深浅拷贝其实对数据在内存中的不同存储方式,在内存中我们分为两种存储方式,栈存储和堆存储。
对于基础数据类型:是直接存储在栈中,而对于复杂数据类型:它的指针存在栈中,而实际数据存在堆中,使用时用栈的指针去找到堆中的数据。
深拷贝和浅拷贝的区别?
首先我们的深浅拷贝之分是只对于Object的,在其它基础数据类型两种拷贝都一样。
浅拷贝:只是把指针复制一份去指原指针指向的数据,并没有真正复制了数据、
深拷贝:不仅复印了指针,同时在堆中也拷贝了一份。
浅拷贝实现:
- Object.assign()
- Array.protopyte.concat() // concat方法用于多个数组的合并。它将新数组的成员,添加到原数组成员的后部,然后返回一个新数组, 用在这里相当于整个用一个空数组合来合并
- Array.protopyte.slice() // slice()方法用于提取目标数组的一部分,返回一个新数组,用在这里相当于整个数组都提取
let obj = {
a:{
name: 'lyy',
age: 18,
},
}
let arr = [1,3,{
name: 'lyy'
}];
let cloneobj = Object.assign(obj);
console.log(cloneobj)
let colnearr = arr.concat();
console.log(colnearr)
let colnearr = arr.slice();
console.log(colnearr)
深拷贝实现:
- JSON.parse(JSON.stringify())
- 手动实现深搜/广搜
JSON.parse(JSON.stringify())
通过把整个对象用JSON.stringify转成JSON字符串,如何在用JSON.parse()拼装成对象,这一来一回就在堆中创造了新的空间。 但是这个做法无法处理对象中有function。
let arr = [1,3,{
name: 'lyy'
}];
let colnearr = JSON.parse(JSON.stringify(arr));
arr[2].name = 'LYY'
console.log(colnearr,arr)
手动实现
//深搜版
function dfs(target,hash_table = new WeakMap()) {
if (typeof target === 'Object') {
let clone = Array.isArray(target) ? [] : {};
if (hash_table.get(target)) return hash_table.get(target);
hash_table.set(target,clone);
for (const key in target) {
clone[key] = dfs(target[key])
}
return clone
} else {
return target
}
}
//广搜版
function bfs(target,hash_table = new WeakMap()) {
if(typeof target !== 'Object') return target
let q = [];
q.push(target);
while (q.length) {
let u = q.shift();
let clone;
if (hash_table.get(u)) {
clone = hash_table.get(u);
} else {
clone = Array.isArray(u) ? [] : {};
hash_table.set(u,clone);
}
for (const key in u) {
let t = u[key];
if(typeof t !== 'Object') {
clone[key] = t
}
if (!hash_table.get(t)) {
clone[key] = Array.isArray(t) ? [] : {};
hash_table.set(t,clone);
q.push(t);
}
}
}
return hash_table.get(target)
}
const target = {
field1: 1,
field2: undefined,
field3: {
child: 'child'
},
field4: [2, 4, 8]
};
target.target = target
console.log(dfs(target),bfs(target))
赋值和浅拷贝的区别是什么?
赋值和浅拷贝之间是有区别的,这个区别只在复杂数据类型时会有
赋值:赋值操作只会对对象的指针进行一个复制,复制的新指针和原指针指向的是同一块内存。
浅拷贝:浅拷贝会先创建一个空的新对象,接着遍历目标对象的每个数据,如果是基础数据类型,则会复制一份放在新对象中,如果是复杂数据类型则只会拷贝指针。