深拷贝与浅拷贝区别
浅拷贝:只复制指向某个对象的指针,而不复制对象本身,新旧对象共享一块内存; 改变一个对象,另一个会随之改变;
深拷贝:复制并创建一个一模一样的对象,不共享内存,修改新对象,旧对象保持不变。
浅拷贝实现
var arr = [1, 2, 3, 4];
var arr2 = arr;
arr2[0] = "okokok";
console.log(arr); // ["okokok", 2, 3, 4]
console.log(arr2); // ["okokok", 2, 3, 4]
像这样简单的赋值便是浅拷贝,一个对象改变,另一个也随之改变。
如何实现深拷贝 下面封装一个方法
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
//数据
var obj={
a:1,
b:"aaa",
c:false,
d:{
e:[3,4,6,8,9],
f:null,
g:[
{id:1,name:"abc",price:100,tag:["自营","特价"]},
{id:2,name:"def",price:200,tag:["自营"]},
{id:3,name:"ghi",price:300,tag:["自营","特价","双十一"]},
{id:4,name:"gkl",price:400,tag:["专柜","双十一"]}
],
h:{
i:/^(?=\D+\d)(?=.*[a-z])(?=.*[A-Z])[0-9a-zA-Z]{8,16}$/i,
j:new Date(),
k:{
}
}
}
}
Object.defineProperties(obj.d.h.k,{
l:{
value:[
[1,2,3,4],
[1,4,3,4],
[1,6,3,4],
]
},
m:{
enumerable:true,
value:document.createElement("div")
},
n:{
writable:true,
value:{
o:[1,2,3],
}
}
})
//封装方法
function cloneObj(source,target){
// 如果目标对象不存在,根据源对象的类型创建一个目标对象
if(!target) target=new source.constructor();
// 获取源对象的所有属性名,包括可枚举和不可枚举
var names=Object.getOwnPropertyNames(source);
// 遍历所有属性名
for(var i=0;i<names.length;i++){
// 根据属性名获取对象该属性的描述对象,描述对象中有configurable,enumerable,writable,value
var desc=Object.getOwnPropertyDescriptor(source,names[i]);
// 表述对象的value就是这个属性的值
// 判断属性值是否不是对象类型或者是null类型
if(typeof desc.value!=="object" || desc.value===null){
// 定义目标对象的属性名是names[i],值是上面获取该属性名的描述对象
// 这样可以将原属性的特征也复制了,比如原属性是不可枚举,不可修改,这里都会定义一样
Object.defineProperty(target,names[i],desc);
}else{
// 新建一个t对象
var t={};
// desc.value 就是源对象该属性的值
// 判断这个值是什么类型,根据类型创建新对象
switch(desc.value.constructor){
// 如果这个类型是数组,创建一个空数组
case Array:
t=[];
break;
// 如果这个类型是正则表达式,则将原值中正则表达式的source和flags设置进来
// 这两个属性分别对应正则desc.value.source 正则内容,desc.value.flags对应修饰符
case RegExp:
t=new RegExp(desc.value.source,desc.value.flags);
break;
// 如果是日期类型,创建日期类型,并且把日期值设置相同
case Date:
t=new Date(desc.value);
break;
default:
// 如果这个值是属于HTML标签,根据这个值的nodeName创建该元素
if(desc.value instanceof HTMLElement)
t=document.createElement(desc.value.nodeName);
break;
}
// 将目标元素,设置属性名是names[i],设置value是当前创建的这个对象
Object.defineProperty(target,names[i],{
enumerable:desc.enumerable,
writable:desc.writable,
configurable:desc.configurable,
value:t
});
// 递归调用该方法将当前对象的值作为源对象,将刚才创建的t作为目标对象
cloneObj(desc.value,t);
}
}
return target;
}
var o=cloneObj(obj);
o.d.f="深拷贝"
o.d.h.k.n.o[0]='深拷贝'
console.log(obj);
console.log(o);
</script>
</body>
</html>