1. 使用JSON.parse来实现
cloneObj = JSON.parse(JSON.stringify(obj))
为什么它可以实现深拷贝
-
序列化和反序列化:
JSON.stringify(obj):将对象转换为 JSON 字符串。这个过程会递归遍历对象的所有属性,并将其转换为字符串形式。JSON.parse(string):将 JSON 字符串解析回一个新对象。这个过程会创建一个新的对象,并填充从字符串中解析出来的属性。
-
断开引用关系:
- 由于经过了序列化(
stringify)和反序列化(parse),原对象和新对象之间没有任何引用关系,因此修改新对象不会影响原对象,反之亦然。
- 由于经过了序列化(
局限性
- 无法处理函数 :函数在序列化时会被忽略,因此新对象中不会包含任何函数属性。
const obj = { a: 1, b: function() {} }; const clone = JSON.parse(JSON.stringify(obj)); console.log(clone.b); // undefined - 无法处理复杂的数据类型:例如
Date、RegExp、Map、Set等复杂数据类型,在序列化时会被转换为普通对象或丢失信息。const obj = { date: new Date(), regExp: /abc/ }; const clone = JSON.parse(JSON.stringify(obj)); console.log(clone.date instanceof Date); // false console.log(clone.regExp instanceof RegExp); // false - Symbol 类型:
Symbol类型的键在序列化时会被忽略。const obj = { [Symbol('a')]: 'value' }; const clone = JSON.parse(JSON.stringify(obj)); console.log(clone); // {}
2.手动递归拷贝
为了克服上述局限性,可以使用更健壮的深拷贝方法,例如:
手动递归拷贝:如你之前提供的代码片段所示,通过递归遍历对象并复制每个属性。
function deepClone(obj){
let cloneObj;
// 判断当输入的数据是简单数据类型时,直接复制
if(obj && typeof obj !== 'object'){
cloneObj = obj;
}
// 当输入的数据是对象或者数组时
else if(obj && typeof obj === 'object'){
// 检测输入的数据是数组还是对象
cloneObj = Array.isArray(obj) ? [] : {};
// 变量数据对象
for(let key in obj){
// 判断对象是否存在key属性
//判断是否存在自定义属性 hasownProperty
if(obj.hasOwnProperty(key)){
if(obj[key] && typeof obj[key] === 'object'){
// 若当前元素类型为对象时,递归调用
cloneObj[key] = deepClone(obj[key]);
}
// 若当前元素类型为基本数据类型
else{
cloneObj[key] = obj[key];
}
}
}
}
return cloneObj;
}
可以进一步改进:
使用 Object.keys() 或 Object.entries():这些方法只会遍历对象自身的可枚举属性,从而避免了显式检查 hasOwnProperty。
if (obj && typeof obj == 'object') {
const cloneObj = Array.isArray(obj) ? [] : {};
Object.keys(obj).forEach(key => {
if (typeof obj[key] === 'object' && obj[key] !== null) {
cloneObj[key] = deepClone(obj[key]);
} else {
cloneObj[key] = obj[key];
}
});
return cloneObj;
}
442

被折叠的 条评论
为什么被折叠?



