1.传统递归
虽然最笨,但是扩展性也最强
function deepClone(value){
if(typeof value !== 'object' || value === null){
return value;
}
//value是对象
const result = Array.isArray(value) ? []:{};
for(let key in value){
//具体是深克隆还是浅克隆看具体需求
//result[key] = value[key]; // 这一步是浅克隆
result[key] = deepClone(value[key]); // 这一步是深克隆
}
return result;
}
const obj = {
a:1,
b:2,
c:function (){}
}
console.log(deepClone(obj)); // {a:1,b:2,c:function(){}} 克隆成功
//如果对象是class的实例化对象
function deepClone1(value){
if(typeof value !== 'object' || value === null){
return value;
}
//value是对象
const result = Array.isArray(value) ? []:{};
//原型保持一致
Object.setPrototypeOf(result,Object.getPrototypeOf(value));
for(let key in value){
//具体是深克隆还是浅克隆看具体需求
//result[key] = value[key]; // 这一步是浅克隆
result[key] = deepClone(value[key]); // 这一步是深克隆
}
return result;
}
class Test{
constructor(){
this.a = 1;
this.b = 2;
}
c(){
console.log('c')
}
}
const obj1 = new Test();
console.log(deepClone1(obj1)); // Test {a:1,b:2} 克隆成功
console.log(deepClone1(obj1).c); //执行成功
//如果对象是class的实例化对象,并且原型上还有自定义属性,上面的方法会将原型上的属性也克隆进去,实际是不希望被克隆进去
function deepClone2(value){
if(typeof value !== 'object' || value === null){
return value;
}
//value是对象
const result = Array.isArray(value) ? []:{};
//原型保持一致
Object.setPrototypeOf(result,Object.getPrototypeOf(value));
for(let key in value){
if(!value.hasOwnProperty(key)){ //判断key是不是value的自由属性
//具体是深克隆还是浅克隆看具体需求
//result[key] = value[key]; // 这一步是浅克隆
result[key] = deepClone(value[key]); // 这一步是深克隆
}
}
return result;
}
class Test{
constructor(){
this.a = 1;
this.b = 2;
}
c(){
console.log('c')
}
}
Test.prototype.d = 1;
const obj2 = new Test();
console.log(deepClone2(obj2)); //克隆成功
//如果里面还有循环引用,上面方法还会导致无限递归
const cache = new WeakMap();
function deepClone3(value){
if(typeof value !== 'object' || value === null){
return value;
}
//判断缓存里有没有
if(cache.has(value)){
retun cache.get(value);
}
//创建对象
const result = Array.isArray(value) ? []:{}; //这里还可以考虑是不是 set,Map
//设置缓存
cache.set(value,result);
//原型保持一致
Object.setPrototypeOf(result,Object.getPrototypeOf(value));
for(let key in value){
if(!value.hasOwnProperty(key)){ //判断key是不是value的自由属性
//具体是深克隆还是浅克隆看具体需求
//result[key] = value[key]; // 这一步是浅克隆
result[key] = deepClone(value[key]); // 这一步是深克隆
}
}
return result;
}
class Test{
constructor(){
this.a = 1;
this.b = 2;
}
c(){
console.log('c')
}
}
Test.prototype.d = 1;
const obj3 = new Test();
obj3.h = obj3
console.log(deepClone3(obj3)); //克隆成功
2.JSON
function deepClone(value){
return JSON.parse(JSON.stringify(value));
}
//普通对象
const obj = {
a:1,
b:2
}
console.log(deepClone(obj)); //{a:1,b:2} 正常
//属性中有特殊类型
const obj1 = {
a:1,
b:2,
c:new Map()
}
console.log(deepClone(obj1)); //{a:1,b:2,c:{}} c变成了普通对象
//属性中有函数
const obj2 = {
a:1,
b:2,
c:function (){}
}
console.log(deepClone(obj2)); //{a:1,b:2} c被丢弃
//属性中有递归引用
const obj3 = {
a:1,
b:2
}
obj3.c = obj3
console.log(deepClone(obj3)); //直接报错 (无法解析递归引用)
3.MessageChannel 通信的方式来传输一个对象借助浏览器的功能来实现一个异步克隆