一、克隆基础数据类型
const deepClone = (target) => target;
二、克隆复杂数据类型
2.1、基础版本
const deepClone = (target) => {
if (target instanceof Object) {
let dist = {};
for (let key in target) {
// 递归调用自己获取到每个值
dist[key] = deepClone(target[key]);
}
return dist;
} else {
return target;
}
};
2.2、数组
const deepClone = (target) => {
if (target instanceof Object) {
let dist;
if (target instanceof Array) {
dist = [];
} else {
dist = {};
}
for (let key in target) {
dist[key] = deepClone(target[key]);
}
return dist;
} else {
return target;
}
};
2.3、函数
const deepClone = (target) => {
if (target instanceof Object) {
let dist;
if (target instanceof Array) {
dist = [];
} else if (target instanceof Function) {
dist = () => {
return target.call(this, ...arguments);
};
} else {
dist = {};
}
// 函数的话不会进到这个 for... in... 循环里面
for (let key in target) {
dist[key] = deepClone(target[key]);
}
return dist;
} else {
return target;
}
}
2.4、正则
const deepClone = (target) => {
if (target instanceof Object) {
let dist;
if (target instanceof Array) {
dist = [];
} else if (target instanceof Function) {
dist = () => {
return target.call(this, ...arguments);
};
} else if (target instanceof RegExp) {
dist = new RegExp(target.source, target.flags);
} else {
dist = {};
}
// 正则、函数的话不会进到这个 for... in... 循环里面
for (let key in target) {
dist[key] = deepClone(target[key]);
}
return dist;
} else {
return target;
}
}
2.5、日期
const deepClone = (target) => {
if (target instanceof Object) {
let dist;
if (target instanceof Array) {
dist = [];
} else if (target instanceof Function) {
dist = () => {
return target.call(this, ...arguments);
};
} else if (target instanceof RegExp) {
dist = new RegExp(target.source, target.flags);
} else if (target instanceof Date) {
dist = new Date(target);
} else {
dist = {};
}
// 日期、正则、函数的话不会进到这个 for... in... 循环里面
for (let key in target) {
dist[key] = deepClone(target[key]);
}
return dist;
} else {
return target;
}
}
三、优化
3.1、忽略原型上的属性
我们在遍历对象的属性的时候,使用的是
for in,for in会遍历包括原型上的所有可迭代的属性。 比如:
let a = Object.create({name:'hello'});
a.age = 14;
但是,事实上我们不应该去遍历原型上的属性,因为这样会导致对象属性非常深。
const deepClone = (target) => {
if (target instanceof Object) {
let dist;
if (target instanceof Array) {
dist = [];
} else if (target instanceof Function) {
dist = () => {
return target.call(this, ...arguments);
};
} else if (target instanceof RegExp) {
dist = new RegExp(target.source, target.flags);
} else if (target instanceof Date) {
dist = new Date(target);
} else {
dist = {};
}
// 日期、正则、函数的话不会进到这个 for... in... 循环里面
for (let key in target) {
// 过滤掉原型身上的属性
if (target.hasOwnProperty(key)) {
dist[key] = deepClone(target[key]);
}
}
return dist;
} else {
return target;
}
}
3.2、环状对象的爆栈问题
用 new Map() 处理一下就好了
const deepClone = (target, cache = new Map()) => {
if (cache.get(target)) {
return cache.get(target);
}
if (target instanceof Object) {
let dist;
if (target instanceof Array) {
// 拷贝数组
dist = [];
} else if (target instanceof Function) {
// 拷贝函数
dist = function() {
return target.call(this, ...arguments);
};
} else if (target instanceof RegExp) {
// 拷贝正则表达式
dist = new RegExp(target.source, target.flags);
} else if (target instanceof Date) {
dist = new Date(target);
} else {
// 拷贝普通对象
dist = {};
}
// 将属性和拷贝后的值作为一个map
cache.set(target, dist);
for (let key in target) {
// 过滤掉原型身上的属性
if (target.hasOwnProperty(key)) {
dist[key] = deepClone(target[key], cache);
}
}
return dist;
} else {
return target;
}
};
3.3、对象过长导致的爆栈问题
正常情况下不会出现那种奇怪的数据结构,一般可以用数组来解决这样的问题,不过那就是另外一种思路了