JS深拷貝與淺拷貝

web-Queen發表於2019-10-21

前言

如何區分深拷貝與淺拷貝,簡單點來說,就是假設B複製了A,當修改A時,看B是否會發生變化
①如果B也跟著變了,說明這是淺拷貝,功力不夠
②如果B沒變,那就是深拷貝,自食其力,修成正果

接下來會分別闡述棧堆,基本資料型別與引用資料型別,這些概念能幫助理解深拷貝與淺拷貝。
淺拷貝案例
在這裡插入圖片描述
在這裡插入圖片描述
有人可能會問:明明b複製了a,為啥修改陣列a,陣列b也跟著變了。這裡就得引入基本資料型別與引用資料型別的概念了。
**資料型別
**
基本資料型別:
number,string,boolean,null,undefined

引用資料型別:
array,object,函式
資料儲存
基本型別–名值儲存在棧
記憶體中,例如let a=1;
當b=a複製時,棧記憶體會新開闢一個記憶體,例如這樣:

在這裡插入圖片描述

在這裡插入圖片描述

所以此時修改a=2,對b並不會造成影響,因為此時的b已自食其力,翅膀硬了,不受a的影響了。當然,let a=1,b=a;雖然b不受a影響,但這也算不上深拷貝,因為深拷貝本身只針對較為複雜的object型別資料。

引用資料型別–名存在棧記憶體中,值存在於堆記憶體中,但是棧記憶體會提供一個引用的地址指向堆記憶體中的值,以上面淺拷貝的例子畫個圖:
在這裡插入圖片描述

當b=a進行拷貝時,其實複製的是a的引用地址,而並非堆裡面的值。
在這裡插入圖片描述
引用資料型別–概念圖
當a[0]=1時進行陣列修改時,由於a與b指向的是同一個地址,所以自然b也受了影響,這就是所謂的淺拷貝了。
在這裡插入圖片描述
要是在堆記憶體中也開闢一個新的記憶體專門為b存放值,就像基本型別那樣,豈不就達到深拷貝的效果了
在這裡插入圖片描述
深拷貝
(1)slice()不帶任何引數,預設返回一個長度和原陣列相同的新陣列
在這裡插入圖片描述
在這裡插入圖片描述
(2)concat()不帶任何引數,把返回陣列和一個空陣列合並後返回,即返回一個長度和原陣列相同的新陣列
在這裡插入圖片描述
在這裡插入圖片描述
(3)直接遍歷,新增到空陣列
在這裡插入圖片描述
在這裡插入圖片描述
(4)ES2015,ES6三點擴充套件運算子
在這裡插入圖片描述
在這裡插入圖片描述
複製陣列:
在這裡插入圖片描述
以上幾種方法都實現了一級拷貝,為什麼叫一級拷貝?
將上述案例,簡單修改下,資料結構巢狀,做兩層巢狀
在這裡插入圖片描述
在這裡插入圖片描述
驗證後發現之前的幾種方法只能拷貝一級資料,那如何拷貝所有層級呢?

接下來介紹兩種常用的方案
①jquery的extend
②JSON的序列化和反序列化
(1)JQ的extend方法
語法:$.extend( [deep ], target, object )
①deep表示是否深拷貝,為true為深拷貝,為false為淺拷貝
②target目標物件,其他物件的成員屬性將被附加到該物件
③object拷貝源物件

在這裡插入圖片描述
在這裡插入圖片描述

單詞:extend延伸
(2)JSON的序列化和反序列化
語法:JSON.parse(JSON.stringify(XXXX))

在這裡插入圖片描述
在這裡插入圖片描述

實現原理:先將物件轉為一個基本資料型別,再執行拷貝
深拷貝和淺拷貝的區別
(1)淺拷貝: 將原物件或原陣列的引用直接賦給新物件,新陣列,新物件/陣列只是原物件的一個引用

(2)深拷貝: 建立一個新的物件和陣列,將原物件的各項屬性的“值”(陣列的所有元素)拷貝過來,是“值”而不是“引用”
深拷貝相關
(1)為什麼要使用深拷貝?
希望在改變新的陣列(物件)的時候,不改變原陣列(物件)

(2)怎麼檢驗深拷貝成功?
改變任意一個新物件/陣列中的屬性/元素, 都不改變原物件/陣列

相關文章