詳解js深淺複製問題

前言

對於前端開發來講,咱們常常可以遇到的問題就是js的深淺複製問題,一般狀況下咱們解決這個問題的方法就是用JSON.parse(JSON.Stringify(xx))轉換或者用相似於Inmmutable這種第三方庫來進行深複製,可是咱們仍是要弄懂其中原理,這樣在開發過程當中能夠省掉不少的坑。javascript

首先讓咱們看幾個例子

// eg1(操做原對象對複製對象無影響):
var a = 'a';
var b =a;
a = 'c';
console.log(b); // a

// eg2(操做原對象對複製對象有影響):
var a = {
a:'a'
};
var b =a;
a.a = 'c';
console.log(b); // {a:'c'}

// eg3(操做原對象對複製對象無影響):
var a = {
a:'a'
};
var b =a.a;
a.a = 'c';
console.log(b); // a

// eg4(操做複製對象對原對象有影響):
var a = {
a:'a'
};
var b = a
b.b = 'b';
console.log(a); // {a:'a',b:'b'}
// eg5(操做複製對象對原對象沒有影響):
var a = {
a:'a'
};
var b = a;
b = {
b:'b'
}
console.log(a); // {a:'a'}

想要理解上面例子發生的緣由就要從數據類型和堆棧內存開始提及html

基本數據類型於引用數據類型

js中存在着兩種數據類型:基本數據類型引用數據類型;
基本數據類型包括:Number、String 、Boolean、Null和Undefined這些常見類型
引用數據類型包括: Object 、Array 、Function這些對象類型前端

堆內存和棧內存

在大多數編程語言中,都存在着這樣的兩個內存空間一個是堆內存(heap),另外一個是棧內存(stack)
當咱們存儲一個基本數據類型的時候,咱們直接放到棧內存中。而當咱們存儲一個引用數據類型的時候,咱們將實際內容存儲在堆內存當中,同時在棧內存中存放着該內容的引用,也就是一個指針
爲何咱們這麼作呢?簡單來講有兩點,一是由於棧內存中存放大小固定的數據,即基本數據類型的數據,同時引用數據類型的指針也是大小固定的,也能夠放進棧內存中,方便程序查找這個數據;而堆內存中存放的是大小不固定的數據,因此適合存放引用數據類型。二這麼分的好處就是在於節省內存資源,便於os合理回收內存java

詳解js中的深淺複製

有了上面的鋪墊,那麼咱們理解起深淺複製就變得容易的許多。
首先咱們要記住:當咱們複製一個基本數據類型的數據時,是新建一個數據同時存放到棧內存中,而當咱們複製一個引用數據類型時,是複製這個引用數據類型的地址,存放到棧內存中,此時堆內存中並無任何變化
讓咱們來看以前的例子
例一和例二就沒什麼好說的了,咱們從例三開始:
a.a是一個字符串類型,是基本類型,因此當b複製的時候是直接複製了一個存放到棧內存中,當a改變時,對b沒有影響
例四:
a是一個對象,是引用數據類型,因此當b複製的時候是複製了a的指針,當對a和b操做時,仍然操做的是堆內存中同一對象,因此a會發生改變
例五:
這個例子看似和上面的很像但實際有很大不一樣,b = {b:'b'}這個操做其實是新建了一個對象
也就是說在堆內存中新建了一個地方,來存放{b:'b'}同時將棧內存中b原來存儲的指向a的指針指向了這個對象,多以a並未發生任何改變編程

參考文獻

https://segmentfault.com/a/11...(重點看這篇,寫的很好!)
http://blog.csdn.net/flyingpi...
https://www.cnblogs.com/cxyin...segmentfault

相關文章
相關標籤/搜索