关于数组和对象的浅拷贝和深拷贝
数组和对象的浅拷贝和深拷贝
-
浅拷贝
- 拷贝的是引用(地址值),修改拷贝后的数据会影响原数据,使得原数据不安全 深拷贝(深度克隆):
- 拷贝的时候生成新数据,修改拷贝后的数据会影响原数据
浅拷贝举例:
//直接赋值
let user={name:"Jack",age:15};
let user1=user;
user1.age=18;
//会影响原数据
console.log(user.age); //18
//拷贝的是地址值
console.log(user.age==user1.age); //true
//Object.assgic方法
let user2=Object.assign(user);
user2.name="Tom";
//会影响原数据
console.log(user.name); //"Tom"
//拷贝的是地址值
console.log(user.name==user2.name); //true
//Array.prototype.concat方法
user=[1,5,{name:"Lily",age:18}];
user1=user.concat();
user1[0]=3;
//user1[2]仍然拷贝的是一个地址值
user1[2].age=20;
//不会影响数据
//因为Array.prototype.concat()返回的是一个新的数组
console.log(user[0]); //1
//false "1==3"
console.log(user[0]==user1[0],`${user[0]}==${user1[0]}`);
//会影响原数据
console.log(user[2].age); //20
//true "20==20"
console.log(user[2].age==user1[2].age,`${user[2].age}==${user1[2].age}`);
//Array.prototype.slice方法
user2=user.slice();
user2[0]="abc";
//user2[2]仍然拷贝的是一个地址值
user2[2].name="Tom";
//不会影响数据
//因为Array.prototype.slice()返回的是一个新的数组
console.log(user[0]); //1
//false "1==abc"
console.log(user[0]==user2[0],`${user[0]}==${user2[0]}`);
//会影响原数据
console.log(user[2].name); //Tom
//true "Tom==Tom"
console.log(user[2].name==user2[2].name,`${user[2].name}==${user2[2].name}`);
上例中调用了Array.prototype.concat(),Array.prototype.slice() 。数组中包含一个带有name和age的对象,这个对象是一个引用类型。保存的仍然是地址值。
解决这个办法,就需要深拷贝,也就是深度克隆
满足拷贝的时候生成新数据,修改新数据不会影响原数据
1.JSON.parse(JSON.stringify())
原理是通过JSON.stringify()将js对象/js数组。转换成字符串类型的json对象/数组。
let user=[1,5,{name:"Tom",age:18}];
//JSON.parse(JSON.stringify()) 深度克隆
let user3=JSON.parse(JSON.stringify(user));
user3[0]=68;
user3[2].name="lisi";
console.log(user[0]); //1;
console.log(user[2].name); //Tom
//false "1==68"
console.log(user[0]==user3[0],`${user[0]}==${user3[0]}`);
//false "Tom==lisi"
console.log(user[2].name==user3[2].name,`${user[2].name}==${user3[2].name}`);
//拿到基本数据类型,再复制。就是深拷贝
//JSON.stringify 返回的是字符串类型
let test=JSON.stringify(user);
console.log(typeof test); //string
2.将数组或对象的每一项都拿到基本数据类型,再复制。就是深拷贝。可通过Object.prototype.tostring.call()和for…in
Object.prototype.tostring.call() 得到数据类型
for…in 拿到数组或对象的每一项
举例:
function checkedType(target)
{
//得到数据类型
return Object.prototype.toString.call(target).slice(8,-1);
}
function clone(target)
{
let res,targetType=checkedType(target);
if(targetType==="Object")
{
res={};
}
else if(targetType==="Array")
{
res=[];
}
else{
return target;
}
//拿到数组或对象的每一项
for (let i in target) {
let value=target[i];
if((checkedType(value)==="Object")||(checkedType(value)==="Array"))
{
res[i]=clone(value);
}
else{
res[i]=value;
}
}
return res;
}
let arr=[2,4,{name:"tom",age:13,color:["blue","pink","green"]}];
let arr1=clone(arr);
arr1[2].color[1]="red";
arr1[1]=5;
//false
console.log(arr1[1]===arr[1]);
//false
console.log(arr1[2].color[1]===arr[2].color[1]);