前言
百科定義:拷貝就是拷貝指向對象的指針,意思就是說:拷貝出來的目標對象的指針和源對象的指針指向的內存空間是同一塊空間,淺拷貝只是一種簡單的拷貝,讓幾個對象公用一個內存,然而當內存銷毀的時候,指向這個內存空間的所有指針需要重新定義,不然會造成野指針錯誤。
拷貝內容總結
數據類型與堆棧的關系
基本類型與引用類型
- 基本類型:undefined,null,Boolean,String,Number,Symbol
- 引用類型:Object,Array,Date,Function,RegExp等
存儲方式
- 基本類型:基本類型值在內存中占據固定大小,保存在
棧內存
中(不包含閉包
中的變量) - 引用類型:引用類型的值是對象,保存在
堆內存
中。而棧內存存儲的是對象的變量標識符以及對象在堆內存中的存儲地址(引用),引用數據類型在棧中存儲了指針,該指針指向堆中該實體的起始地址。當解釋器尋找引用值時,會首先檢索其在棧中的地址,取得地址后從堆中獲得實體。
注意:
閉包
中的變量並不保存在棧內存中,而是保存在堆內存中。這一點比較好想,如果閉包
中的變量保存在了棧內存
中,隨着外層中的函數從調用棧中銷毀,變量肯定也會被銷毀,但是如果保存在了堆內存中,內存函數仍能訪問外層已銷毀函數中的變量。看一段對應代碼理解下:
function A() { let a = 'koala' function B() { console.log(a) } return B }
基本數據類型復制配圖:
結論:在棧內存中的數據發生數據變化的時候,系統會自動為新的變量分配一個新的之值在棧內存中,兩個變量相互獨立,互不影響的。
引用數據類型復制
看一段代碼
let a = {x:'kaola', y:'kaola1'} let b = a; b.x = '程序員成長指北'; console.log(a.x); // 程序員成長指北
引用類型的復制,同樣為新的變量b分配一個新的值,報錯在棧內存中,不同的是這個變量對應的具體值不在棧中,棧中只是一個地址指針。兩個變量地址指針相同,指向堆內存中的對象,因此b.x發生改變的時候,a.x也發生了改變。
淺拷貝
淺拷貝定義:
不知道的api我一般比較喜歡看MDN,淺拷貝的概念MDN官方並沒有給出明確定義,但是搜到了一個函數Array.prototype.slice,官方說它可以實現原數組的淺拷貝。
對於官方給的結論,我們通過一段代碼驗證一下,並總結出淺拷貝的定義。
-
var a = [ 1, 3, 5, { x: 1 } ]; var b = Array.prototype.slice.call(a); b[0] = 2; console.log(a); // [ 1, 3, 5, { x: 1 } ]; console.log(b); // [ 2, 3, 5, { x: 1 } ];
從輸出結果可以看出,淺拷貝后,數組a[0]並不會隨着b[0]改變而改變,說明a和b在棧內存中引用地址並不相同。
淺拷貝定義:
通過這個官方的slice
淺拷貝函數分析淺拷貝定義
:
新的對象復制已有對象中非對象屬性的值和對象屬性的引用。如果這種說法不理解換一種一個新的對象直接拷貝已存在的對象的對象屬性的引用,即淺拷貝。
深拷貝操作
說了賦值操作和淺拷貝操作,大家是不是已經能想到什么是深拷貝了,下面直接說深拷貝的定義。
深拷貝定義
深拷貝會另外拷貝一份一個一模一樣的對象,從堆內存中開辟一個新的區域存放新對象,新對象跟原對象不共享內存,修改新對象不會改到原對象。