深拷贝和浅拷贝

  • 值类型的拷贝的是拷贝值的副本,都互不影响。
  • 深拷贝和浅拷贝是针对引用类型(如数组、对象)的拷贝。

一、浅拷贝

  • 引用类型拷贝的是“引用“(即指针),之后一方改变都会影响到到另一方。

两种情况

  • 情况一:直接赋值,直接拷贝源的是对象(数组)的引用,相互影响。
  • 情况二:不是直接赋值(拷贝源对象的实例)
  • 属性值是值类型时,直接拷走值的副本,两个都互不影响;
  • 属性值的引用类型时,拷贝的是引用(地址),一方改变都会影响到到另一方。

实现

对象拷贝:

const obj = {
name:"hjj",
info:{
age:18,
props:["阳光","开朗"]
}
}
//1. ...实现
let copy1={...obj}
console.log(copy1===obj)//false
console.log(copy1.info === obj.info);// true
copy1.info.age=181;
console.log(obj.info.age);//181
copy1.name='HHH1';
console.log(copy1.name,obj.name);//HHH1 hjj


// 2. Object.assign实现
let copy2=Object.assign({},obj)
console.log(copy2===obj)//false
console.log(copy2.info === obj.info);// true
copy2.info.age=182;
console.log(obj.info.age);//182
copy2.name='HHH2';
console.log(copy2.name,obj.name);//HHH2 hjj

// 3. for in实现
let copy3={}
for(let key in obj){
copy3[key]=obj[key]
}
console.log(copy3===obj)//false
console.log(copy3.info === obj.info);// true
copy3.info.age=183;
console.log(obj.info.age);//183
copy3.name='HHH3';
console.log(copy3.name,obj.name);//HHH3 hjj

//4.直接赋值,直接拷贝源对象的引用
let copy4=obj
console.log(copy4===obj)//true
console.log(copy4.info === obj.info);// true
copy4.info.age=184;
console.log(obj.info.age);//184
copy4.name='HHH4';
console.log(copy4.name,obj.name);//HHH4 HHH4


数组拷贝:

const arr=[
{
name:"hjj",
info:{
age:18,
props:["阳光","开朗"]
}
},
0
]
//1. ...实现
let copy1=[...arr]
console.log(copy1===arr);//false
console.log(copy1[0].info === arr[0].info);// true
copy1[0].info.age=181;
console.log(arr[0].info.age);//181
copy1[1]=1
console.log(copy1[1],arr[1]);//1 0

//2.Array.from实现
let copy2=Array.from(arr);
console.log(copy2===arr);//false
console.log(copy2[0].info === arr[0].info);// true
copy2[0].info.age=182;
console.log(arr[0].info.age);//182
copy2[1]=2
console.log(copy2[1],arr[1]);//2 0


// 3、forEach实现
let copy3 = [];
arr.forEach(item=>copy3.push(item));
copy3 = Array.from(arr);
console.log(copy3 === arr);// false
console.log(copy3[0].info === arr[0].info);// true
copy3[0].info.age=183;
console.log(arr[0].info.age);//183
copy3[1]=3
console.log(copy3[1],arr[1]);//3 0

// 4、map实现
let copy4 = arr.map(item=>item);
console.log(copy4 === arr);// false
console.log(copy4[0].info === arr[0].info);// true
copy4[0].info.age=184;
console.log(arr[0].info.age);//184
copy4[1]=4
console.log(copy4[1],arr[1]);//4 0

//5、slice()
let copy5=arr.slice()
console.log(copy5===arr)//true
console.log(copy5[0].info === arr[0].info);// true
copy5[0].info.age=185;
console.log(arr[0].info.age);//185
copy5[1]=5
console.log(copy5[1],arr[1]);//5 0

//6.直接赋值,直接拷贝源数组的引用
let copy6=arr
console.log(copy6===arr)//true
console.log(copy6[0].info === arr[0].info);// true
copy6[0].info.age=186;
console.log(arr[0].info.age);//186
copy6[1]=6
console.log(copy6[1],arr[1]);// 6 6


二、深拷贝

  • 创建一个新的对象和数组,将原对象的各项属性的“值”(数组的所有元素)拷贝过来,拷贝的是“值”而不是“引用”。
  • 改变新的数组(对象)的时候,不会改变原数组(对象)。互不影响

实现

方法一:JSON.parse(JSON.stringify(obj))

  • 局限:函数不能复制;原型链搞没了...
const obj = {
name:"hjj",
info:{
age:18,
props:["阳光","开朗"]
}
}
let copy1=JSON.parse(JSON.stringify(obj));
console.log(copy1===obj)//false
console.log(copy1.info === obj.info);// false
copy1.info.age=181;
console.log(obj.info.age);//18


方法二:递归拷贝

function deepClone(obj){
// 判断是否数组或对象,确定初始值
let copy = obj instanceof Array ? [] : {}
for (let i in obj) {
if (obj.hasOwnProperty(i)) {
copy[i] = typeof obj[i] === 'object' ? deepClone(obj[i]) : obj[i]
}
}
return copy
}
const obj = {
name:"hjj",
info:{
age:18,
props:["阳光","开朗"]
}
}
let copy1=deepClone(obj);
console.log(copy1===obj)//false
console.log(copy1.info === obj.info);// false
copy1.info.age=181;
console.log(obj.info.age);//18


**方法三:jQuery.extend() **

  • ​$.extend( [deep], target, object1 [, objectN ] )​
  • 用于将一个或多个对象内容合并到目标对象
  • deep:默认false-浅拷贝,true-深拷贝
var a = [{m:1}, {n:2},3]; 
var b =[];
$.extend(true,b,a);
console.log(a === b);// false
a[0].m = 4;
console.log(b[0].m)//1