賦值
當(dāng)把一個對象a賦值給另外一個對象b時荣德,賦的值是對象a在棧中的地址闷煤,而不是堆中的數(shù)據(jù)。
let a={
name:'xiaoming',
age:21,
grade:{
language:60,
math:81,
english:99,
science:94
},
}
let b=a
b.name='xiaowang'
b.grade.language=90
console.log('a',a)
console.log('b',b)
結(jié)果分析:對象b和對象a指向同一地址涮瞻,無論哪個對象發(fā)生改變鲤拿,另外一個對象都會聯(lián)動變化.
淺拷貝
淺拷貝它會創(chuàng)建一個新對象,不會指向同一個地址饲宛,只會賦值制對象的非對象屬性
(如果屬性是基本類型,拷貝的就是基本類型的值嗜价;如果屬性是內(nèi)存地址(引用類型)艇抠,拷貝的就是內(nèi)存地址)
ES6中有個淺拷貝的方法Object.assign(target, ...sources)。
let a = {
name: '小明',
age: 21,
grade: {
language: 78,
math: 81,
english: 99,
science: 94
},
}
let b = {}
Object.assign(b,a)
b.name = '小花'
b.grade.english = 9
console.log('a', a)
console.log('b', b)
結(jié)果分析:
b對象改變 name的值和grade對象久锥,a對象只有g(shù)rade對象的值發(fā)生改變家淤,name未受影響。
因?yàn)樯桑琻ame是基本類型絮重,b改變自身值,a 不會改變歹苦;而grade是一個對象青伤,為引用類型,b拷貝的是該對象的地址殴瘦,與a指向同一個地址狠角,所以b改變grade對象的值時,a也發(fā)生變化蚪腋。
深拷貝
深拷貝會另外拷貝一份一個一模一樣的對象,但是不同的是會從堆內(nèi)存中開辟一個新的區(qū)域存放新對象,新對象跟原對象不再共享內(nèi)存丰歌,修改賦值后的對象b不會改到原對象a。
實(shí)現(xiàn)方式
1屉凯、JSON.parse(JSON.stringify())
原理
用JSON.stringify將JSON對象轉(zhuǎn)成JSON字符串立帖,
再用JSON.parse()把字符串解析成對象,一去一來悠砚,新的對象產(chǎn)生了晓勇,而且對象會開辟新的棧,實(shí)現(xiàn)深拷貝。
缺點(diǎn)
由于用到了JSON.stringify()宵蕉,這也會導(dǎo)致一系列的問題酝静,因?yàn)橐獓?yán)格遵守JSON序列化規(guī)則:原對象中如果含有Date對象,JSON.stringify()會將其變?yōu)樽址勐辏蟛⒉粫⑵溥€原為日期對象别智。或是含有RegExp對象稼稿,JSON.stringify()會將其變?yōu)榭諏ο蟀邕叮瑢傩灾泻蠳aN、Infinity和-Infinity遇八,則序列化的結(jié)果會變成null复凳,如果屬性中有函數(shù),undefined,symbol則經(jīng)過JSON.stringify()序列化后的JSON字符串中這個鍵值對會消失,因?yàn)椴恢С帧?/p>
2谋右、手寫遞歸方法
遞歸方法實(shí)現(xiàn)深度克隆
/**
* 深拷貝
* @param {Object} obj 要拷貝對象
*/
function deepClone(obj = {}) {
if (typeof obj !== 'object' || obj == null) {
// 不是對象硬猫,或者是null
return obj
}
//初始化返回結(jié)果
let result
if (obj instanceof Array) {
result =[]
}else{
result = {}
}
for (const key in obj) {
//保證key不是原型的屬性
if (obj.hasOwnProperty(key)) {
//遞歸調(diào)用!改执!
result[key] = deepClone(obj[key])
}
}
//返回結(jié)果
return result
}
結(jié)果分析:b對象改變 name的值和grade對象啸蜜,a均未受到影響,
以為b跟a不共享內(nèi)存地址辈挂,是從堆內(nèi)存中開辟一個新的區(qū)域存放的新對象衬横。