JS实现对象的深复制
function cloneObject(source,target){
var list=["number","string","boolean","undefined","null","function"];
if(target===undefined){
// 判断源对象是否是HTML标签
if(HTMLElement.prototype.isPrototypeOf(source)){
// 根据这个源对象的nodeName创建一个DOM对象
target=source.cloneNode(false);
}else{
// 根据源对象的构造函数创建一个新对象
target=new source.constructor();
}
}
// 获取源对象中所有的属性名
var names=Object.getOwnPropertyNames(source);
// 遍历所有属性名
for(var i=0;i<names.length;i++){
// 获取源对象中该属性名的描述对象
var desc=Object.getOwnPropertyDescriptor(source,names[i]);
// 判断该属性的值是否是基础数据类型
if(list.includes(typeof desc.value)){
// 如果是基础数据类型,直接将该描述对象设置给目标对象的该属性
Object.defineProperty(target,names[i],desc);
}else{
// 创建一个新引用型属性值
var t;
// 因为DOM是特殊不能使用new创建,因此判断该对象是否是DOM类型
if(HTMLElement.prototype.isPrototypeOf(desc.value)){
t=desc.value.cloneNode(false);
// 复制这个类型给这个对象
}else{
// 将属性值的类型分类判断
switch(desc.value.constructor){
case RegExp:
// 如果正则表达式时,需要将source和flags带入
t=new RegExp(desc.value.source,desc.value.flags);
break;
case Date:
// 日期属性需要将日期直接带入
t=new Date(desc.value);
break;
case Symbol:
// 直接创建Symbol,不能复制相同
t=Symbol();
break;
case Set:
// Set类型需要将values带入set
t=new Set(desc.value.values());
break;
break
case Map:
// map需要将entries带入map
t=new Map(desc.value.entries());
break;
default:
// 其他,包括数组和对象可以直接创建新的类别
t=new desc.value.constructor();
break;
}
}
// 将描述对象的各种值设置给该对象的属性
var o={}
o.value=t;
if(desc.enumerable)o.enumerable=desc.enumerable;
if(desc.writable)o.writable=desc.writable;
if(desc.configurable)o.configurable=desc.configurable;
if(desc.set) o.set=desc.set;
if(desc.get) o.get=desc.get;
Object.defineProperty(target,names[i],o);
// 递归将获取的该属性值复制给创建的这个引用对象
cloneObject(desc.value,t);
}
}
return target;
}