淺析前端的堆棧原理以及深淺拷貝原理
首先來看一個案例
const obj = {name:'hzw',age:18
}
let objName2 = obj
objName2.age = 12
console.log(obj,objName2) // {name: 'hzw', age: 12} {name: 'hzw', age: 12}
這里是不是很奇怪,為什么,為什么我改變objName2的值,第一個obj的值也發生了改變。
那么現在就有人說了,這淺拷貝嘛,有啥好難理解的
那又是為什么會造成這種情況呢,這個時候就必須對前端數據存儲的堆棧空間有所了解了,首先來說棧
棧:
第一點:我們必須要明白,前端的堆棧空間是怎么存儲的。
前端的簡單數據類型,都是存在一個棧內存中,不涉及指針
每次去新聲明一個簡單數據類型的變量,他都會新開一個棧地址,而新開的棧地址,與原變量是兩個沒有聯系的個體
所以你會發現,簡單數據類型不會存在有深淺拷貝的說法。
即衍生出了一個JSON.parse(JSON.stringify(xxx))對一個對象進行深拷貝的方法,原理后面再講
堆:
前面已經說了,前端JS的簡單數據類型,都是存在一個棧內存中
而JS中,他的引用數據類型的值,則是放在一個堆空間中,由指針去指向這個堆空間
下面給一張圖來對他進行一個解析
堆棧圖
現在我們回到第一個案例
const obj = {name:'hzw',age:18
}
let objName2 = obj
objName2.age = 12
console.log(obj,objName2) // {name: 'hzw', age: 12} {name: 'hzw', age: 12}
為什么這個值發生變化了呢
因為第一個變量obj,它自己的指針,指向了堆空間中的值{name:'hzw',age:18
},
而第二個變量擁有了一個新的指針,但是這個指針指向的堆空間的值也是{name:'hzw',age:18
},
所以就出現了雖然他們的指針不同,但是所指向的堆空間都是同一個(共用了同一個堆空間)
所以當第二個的age發現了變化,第一個也會變
如下圖:
而為什么這樣,obj的值又不會發生改變呢
const obj = {name:'hzw',age:18
}
let objName2 = JSON.parse(JSON.stringify(obj))
objName2.age = 12
console.log(obj,objName2) // {name: 'hzw', age: 18} {name: 'hzw', age: 12}
下面進行一個詳細的解析
`JSON.stringify(obj)` 將對象 `obj` 序列化為 JSON 字符串,他變成了一個簡單數據類型`JSON.parse(...)` 將這個 JSON 字符串重新解析為一個新的對象,從而產生了一個新的對象即他新開辟了一個堆空間,使的這兩個指針指向的并不是同一個堆空間,所以這個時候obj的值就不會發生改變
同時這個方法也不是萬能的,只能說滿足絕大多數的深拷貝需求
使用 JSON.parse(JSON.stringify(obj)) 進行深拷貝的方法有局限性:
1. 無法復制函數、正則表達式、Date 對象等特殊類型的屬性。
2. 會忽略 undefined 值。
3. 會忽略循環引用的情況。
##### 好了,通過這篇文章,是不是對JS中的堆棧類型以及深淺拷貝都有所了解呢。