用js處理資料的時候經常遇到需要保留原資料的情況,有時把資料賦給新的變數並不能解決問題, 原因是記憶體中僅保留乙份資料。這時候需要製作乙份資料的副本。
只有複雜型別變數(引用型別)存在深拷貝與淺拷貝的問題,而基本型別沒有深拷貝的概念。
要弄明白拷貝,首先要明白js中物件的組成。在js中一切例項皆是物件,具體分為原始型別和合成型別。原始型別物件指的是number、string、boolean等,合成型別物件指的是array、object以及function。
「堆記憶體」和「棧記憶體」
基本型別變數作為「值」儲存於「棧記憶體」中。
引用型別變數作為乙個指標儲存在棧記憶體中,指向儲存在「堆記憶體」中的引用型別的值
堆和棧的區別可以用如下的比喻來看出:
使用棧就象我們去飯館裡吃飯,只管點菜(發出申請)、付錢、和吃(使用),吃飽了就走,不必理會切菜、洗菜等準備工作和洗碗、刷鍋等掃尾工作,他的好處是快捷,但是自由度小。
使用堆就象是自己動手做喜歡吃的菜餚,比較麻煩,但是比較符合自己的口味,而且自由度大。
深拷貝和淺拷貝
淺拷貝:拷貝乙個變數的時候,複製了棧記憶體,沒有複製堆記憶體。
深拷貝:拷貝乙個變數的時候,複製了棧記憶體,同時也複製了堆記憶體。
淺拷貝淺拷貝可以理解為就是複製乙份來引用,所有引用物件都指向乙份資料,並且都可以修改這份資料。 對於字串型別,淺拷貝是對值的拷貝,對於物件來說,淺拷貝是對物件位址的拷貝,也就是複製 的結果是兩個物件指向同乙個記憶體位址,修改其中乙個物件的屬性,則另乙個物件的屬性也會改變
深拷貝深拷貝則是複製變數值,對於非基本型別的變數,則遞迴至基本型別變數後,再複製。 深複製不同於淺複製,它會開闢新的記憶體位址,兩個物件對應兩個不同的位址,修改 乙個物件的屬性,不會改變另乙個物件的屬性
1.如何實現陣列深拷貝和淺拷貝?
2.深拷貝與淺拷貝的優缺點
方法一: 用js的slice函式來實現
方法二:用js的concat方法
slice方法
對於array物件的slice函式,
返回乙個陣列的一段。(仍為陣列)
arrayobj.slice(start, [end])
引數:arrayobj
必選項。乙個 array 物件。
start
必選項。arrayobj 中所指定的部分的開始元素是從零開始計算的下標。
end可選項。arrayobj 中所指定的部分的結束元素是從零開始計算的下標。
concat方法
concat() 方法用於連線兩個或多個陣列。
該方法不會改變現有的陣列,而僅僅會返回被連線陣列的乙個副本。
語法
arrayobject.concat(arrayx,arrayx,......,arrayx)
說明
返回乙個新的陣列。該陣列是通過把所有 arrayx 引數新增到 arrayobject 中生成的。如果要進行 concat() 操作的引數是陣列,那麼新增的是陣列中的元素,而不是陣列。
淺拷貝的缺點是如果你改變了物件b所指向的記憶體位址,你同時也改變了物件a指向這個位址的字段。
深拷貝,這種方式會完全拷貝所有資料,優點是b與a不會相互依賴(a,b完全脫離關聯), 缺點是拷貝的速度更慢,代價更大 (可理解為耗費了更多記憶體空間)。
demo
其他深拷貝的方法
json物件的轉換方法,兩次轉換
閉包中儲存到記憶體當中的資料是儲存到棧中還是堆中的
都有物件的深拷貝是怎麼弄得
如何實現深拷貝和淺拷貝
我們先來說一下淺拷貝 var obj var b obj console.log b 輸出結果為1但是淺拷貝會存在乙個問題,通過淺拷貝拷貝了乙個引用型別,如果我們去修改obj會怎麼樣?var obj var b obj 修改obj裡面的a屬性 obj.a 2console.log b 輸出結果再來看...
陣列拷貝(深拷貝 淺拷貝)
底層都是使用system.arraycopy object src,int srcpos,object dest,int destpos,int length 方法完成陣列元素拷貝任務的 方法說明 如果newlength original.length,那麼會將原陣列中前newlength個元素拷貝...
如何理解深拷貝和淺拷貝
首先我們先記住乙個結論 編譯器自動生成的拷貝構造和賦值運算子是memcpy的乙個過程。例項過程以結構體代替,在c 中struct和class除了預設訪問許可權基本等同。struct teststruct1 int main 拷貝構造直接將onevar的記憶體空間拷貝到twovar的記憶體空間中。考慮...