前言
实现一个深拷贝:可以复制undefined,function.能够保证RegExp复制并且类型不变.
可以参考本文来实现如Date()的深拷贝
知识点
getOwnPropertyNames
getOwnPropertyNames返回指定对象内部的所有属性名组成的数组
getOwnPropertyDescriptor
getOwnPropertyDescriptor返回某个对象属性的描述对象,举个例子看描述对象的内容
var obj2={ g:/^[a-z]{1,2}$/gi } let desc=Object.getOwnPropertyDescriptor(obj2,'g') console.log('desc',desc)
value的具体打印,可以看到描述对象的value上可以访问到原型对象:desc.value.constructor指向了RegExp.在拷贝正则的时候,我们就可以利用new desc.value.constructor生成一个新正则
Object.defineProperty
在对象上定义新属性和属性值
实现
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> </head> <body> <script> function deepClone(newObj,source){ //getOwnPropertyNames返回指定对象内部的所有属性名组成的数组 var names=Object.getOwnPropertyNames(source); for(let i=0;i<names.length;i++){ //getOwnPropertyDescriptor返回某个对象属性的描述对象 var desc=Object.getOwnPropertyDescriptor(source,names[i]) console.log('desc',desc) //当前属性值是对象时 if(typeof desc.value==="object" && desc.value!==null){ var obj; //desc.value.constructor指向了原型,比如RegExp switch(desc.value.constructor){ case RegExp:
//等于 new RegExp() obj=new desc.value.constructor(desc.value.source,desc.value.flags); break; case Function: obj=new desc.value.constructor(desc.value.source,desc.value.flags); break; default: obj=new desc.value.constructor() } deepClone(obj,desc.value); Object.defineProperty(newObj,names[i],{ value:obj, enumerable:desc.enumerable, writable:desc.writable, configurable:desc.configurable }); }else{ Object.defineProperty(newObj,names[i],desc); } } return newObj; } var obj={ a:1, b:"a", d:{ e:undefined, f:[1,2,3], g:/^[a-z]{1,2}$/gi }, h:function(){ console.log(11) } } var obj1=deepClone({},obj); </script> </body> </html>
执行代码,查看打印结果,确定是否完成深拷贝
1.正则的desc描述符
console.log('desc',desc)
2.深拷贝后的obj1,可以看出和obj完全相同
console.log('深拷贝后的obj1',obj1)
3.修改obj1并查看obj是否被影响.可以看到obj没有被影响,我们的深拷贝成功
obj1.d={'di':'didi'}
console.log('修改后obj1',obj1);
console.log('obj1修改后的obj',obj);
4.执行obj1拷贝的方法
obj1.h()
打印出11