# 关于对象(数组)的深浅克隆
let obj = {
a: 100, // 普通数据类型
b: [1, 2, 3, { x: 10 }, [1, 2, 3]], // 数组
c: {
// 对象
x: 10,
},
d: /^\d+$/, // 正则表达式
};
# 浅克隆
# 常规方法
let easyCopy = function (obj) {
let newObj = {};
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
newObj[key] = obj[key];
}
}
return newObj;
};
let obj2 = easyCopy(obj);
解析:浅拷贝的话只能拷贝一层
# ES6 方法
let obj2 = { ...obj };
# 深克隆
# 使用 JSON 解析实现简版深克隆
let obj2 = JSON.parse(JSON.stringify(obj));
解析:该方法只能深拷贝对象里面只有普通对象和普通类型数据的对象,针对有特殊类型的值,比如 Date,RegExp,Function 等等,该方法就不能应对了,为什么呢?请看如下代码:
# Date 类型
var d = new Date();
console.log(JSON.parse(JSON.stringify(d)));
//=>输出结果为:"2020-08-19T13:45:18.729Z"
//变成了一个字符串,但是d应该是一个Date类型的对象才对!
# RegExp 类型
var r = new RegExp();
console.log(JSON.parse(JSON.stringify(r)));
//=>输出结果为:{}
//变成了一个空对象,同理,这里正确应该是一个RegExp类型的对象才对
# ...
# 使用递归方式实现深克隆
为了解决以上这个问题,我们使用递归写一个可扩展的通用性强的深拷贝的方法,祭出代码如下:
let deepCopy = function (obj) {
if (typeof obj !== "object") {
return obj;
}
if (obj === null) {
return null;
}
if (obj instanceof Date) {
return new Date(obj);
}
if (obj instanceof RegExp) {
return new RegExp(obj);
}
// ...
// 继续添加需要特殊处理的类型
let newObj = new obj.constructor();
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
newObj[key] = deepCopy(obj[key]);
}
}
return newObj;
};
obj2 = deepCopy(obj);
# 关键代码解析
看到上面的代码,你或许有疑问:为什么没有处理数组的情况呢?是不是太不严谨了?
关键代码就在这一句!
let newObj = new obj.constructor();
为什么这里不使用下面的代码呢?
let newObj = {};
// 或者
let newOjb = new Object();
这里使用对象的构造函数(constructor)创建新对象的好处在于:这样你创建的对象的类型就不会局限于 Object,就比如数组类型(Array)的我们看看,创建之后是什么?
var arr = [];
var arr1 = new arr.constructor();
//=> arr1的结果是:[]
这也就是上面 deepCopy 方法中没有考虑数组情况的原因。