深浅拷贝主要针对对象而言的。
浅拷贝:只拷贝对象最外面一层的基本数据类型的数据;若属性是对象,只拷贝其引用。
深拷贝:拷贝多层数据;每一层级别的数据都会拷贝。
深拷贝会把对象里所有的数据重新复制到新的内存空间,是最彻底的拷贝。
|
赋值可以是基本数据类型和引用数据类型,拷贝是针对对象(引用数据类型)。
赋值 |
基本数据类型 |
let a=1,b=a;
操作数据的时候a,b值互不影响。b=a
实际此时b与a指向同一栈地址取其存放的值,只不过b或a值发生改变后,会开辟新的栈内存存放其值,指针也相应发生改变。
引用数据类型 |
const Jane={name:'Jane',age:22};
let Jim=Jane;
Jane和Jim都指向同一堆地址(对象所在)。无论谁操作了对象的值,都会彼此影响。
拷贝 |
浅拷贝 |
会为对象第一层属性值是基本数据类型的数据开辟完整内存空间复制存放,如果值是引用类型,只是赋值其引用。
也就是说,浅拷贝的对象第一层属性值是基本类型的属性是完全独立于原始对象的,引用类型的话还是两者共享。
经典for...in
实现浅拷贝
const Tom={name:'Tom',age:24,company:{name:'Tencent',addr:'SZ'}};
let Tony={}
for (let key in Tom) {
Tony[key]=Tom[key]
}
Tony.name='Tony'
Tony.company.name='DaJiang'
console.log(Tom);
console.log(Tony);
深拷贝 |
原对象与拷贝对象属性互不影响。
🌰递归实现深拷贝
function deepColon(obj){
let colon=Array.isArray(obj)?[]:{}
for (let [key,value] of Object.entries(obj)) {
if(value&&typeof value==='object'){
colon[key]=deepColon(value)
}else{
colon[key]=value;
}
}
return colon;
}
|
浅拷贝 |
Object.assign() |
// 语法1
obj2 = Object.assgin(obj2, obj1);
// 语法2
Object.assign(目标对象, 源对象1, 源对象2...);
解释:将obj1 拷贝给 obj2。执行完毕后,obj2 的值会被更新。
作用:将 obj1 的值追加到 obj2 中。如果对象里的属性名相同,会被覆盖。
从语法2中可以看出,Object.assign() 可以将多个“源对象”拷贝到“目标对象”中。
let Tom={name:'Tom',location:{nation:'CHN',city:'XX'}}
let Tony=Object.assign({},Tom,{age:24,name:'Tony'})
slice() |
slice数组切割,不设置参数,默认从下标0开始,并返回一个新数组。如果是一维数组,那也算完全拷贝了。
const arr=[1,2,3]
let obj=arr.slice()
🌰证明slice浅拷贝
const arr=[1,2,3,[4,5]]
let obj=arr.slice()
obj[0]=0
obj[3][0]=6//不可obj[3]=6 这样是直接指向另外一个对象的地址了而不是在原对象上改变值
concat() |
concat数组拼接,不设置参数,则返回原数组的一个副本。如果是一维数组,那也算完全拷贝了。
const arrA=[1,2,3,[4,5]]
let arrB=arrA.concat()
arrB[3][1]=0
console.log(arrA);
…拓展运算符 |
ES6拓展运算符可以实现数组浅拷贝。如果是一维数组,那也算完全拷贝了。
const a=[1,2,[1,2]]
let [...b]=a
let c=[...a]
深拷贝 |
通过JSON对象实现深拷贝
弊端:如果obj里有NaN、Infinity和-Infinity,则序列化的结果会变成null;
如果obj里有函数,undefined,则序列化的结果会把函数或 undefined丢失;
…
const XiaoMing={name:'XiaoMing',age:22,company:{name:'Tencent',addr:'SZ'}};
let XiaoHong=JSON.parse(JSON.stringify(XiaoMing));