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方法中没有考虑数组情况的原因。