16、js拷贝(浅拷贝,深拷贝)
原生方法:
实现浅拷贝的方法
1、使用Object.assign():
let shallowCopy = Object.assign({
},originalObject);
2、使用Spread运算符:
let shallowCopy = {
...originalObject };
3、使用for……in 循环:
let shallowCopy = {
};
for (let key in originalObject) {
shallowCopy[key] = originalObject[key];
}
实现深拷贝的方法
使用JSON.parse()和JSON.stringify()
let deepCopy = JSON.parse(JSON.stringify(originalObject));
- 源对象中存在函数
- 源对象存在循环引用
- 源对象中存在Map、Set数据类型
出现上述情况将会导致严重后果,上述方法会自动忽略
手写深拷贝函数
function deepClone(obj) {
// 如果该对象不是对象(即为基本数据类型),则直接返回该值
if (typeof obj != "object") {
return obj;
}
// 如果该对象是数组,则创建一个空数组;否则创建一个空对象
let res = Array.isArray(obj) ? [] : {
};
// 遍历该对象的属性
for (let key in obj) {
// 如果该属性是该对象的自身属性(即不是继承自原型链的属性)
if (obj.hasOwnProperty(key)) {
// 将该属性的值复制一份
res[key] = deepClone(obj[key]);
}
}
// 返回复制的对象
return res;
}
//测试
let obj = {
a: 1,
b: [1, 2, 3],
c: {
d: 1
}
}
obj.self = obj;
console.log(copyObj);
上述方法遇到循环访问将会无限递归
function deepClone(obj) {
// 创建一个 Map 对象,用来存储已经复制的对象
let map = new Map();
// 定义 doClone 函数,用于递归复制对象
function doClone(obj) {
// 如果该对象不是对象(即为基本数据类型),则直接返回该值
if (typeof obj != "object") {
return obj;
}
// 如果该对象已经被复制过,则直接返回复制的对象
if (map.has(obj)) return map.get(obj);
// 如果该对象是数组,则创建一个空数组;否则创建一个空对象
let res = Array.isArray(obj) ? [] : {
};
//将创建的对象放入Map中
map.set(obj, res);
// 遍历该对象的属性
for (let key in obj) {
// 如果该属性是该对象的自身属性(即不是继承自原型链的属性)
if (obj.hasOwnProperty(key)) {
// 将该属性的值复制一份
res[key] = doClone(obj[key]);
}
}
// 返回复制的对象
return res;
}
// 返回递归调用 doClone 函数的结果,即深拷贝后的对象
return doClone(obj);
}