一、含義:深拷貝和淺拷貝最根本的區別在於是否真正獲取一個對象的復制實體,而不是引用。假設B復制了A,修改A的時候,看B是否發生變化:
如果B跟着也變了,說明是淺拷貝,拿人手短!(修改堆內存中的同一個值)如果B沒有改變,說明是深拷貝,自食其力!(修改堆內存中的不同的值)
- 淺拷貝(shallowCopy)只是增加了一個指針指向已存在的內存地址,僅僅是指向被復制的內存地址,如果原地址發生改變,那么淺復制出來的對象也會相應的改變。
- 深拷貝(deepCopy)是增加了一個指針並且申請了一個新的內存,使這個增加的指針指向這個新的內存。 在計算機中開辟一塊新的內存地址用於存放復制的對象。
- 基本數據類型:number,string,boolean,null,undefined,symbol以及未來ES10新增的BigInt(任意精度整數)七類。
引用數據類型(Object類)有常規名值對的無序對象{a:1},數組[1,2,3],以及函數等。
而這兩類數據存儲分別是這樣的:
a.基本類型--名值存儲在棧內存中,例如let a=1; 當你b=a復制時,棧內存會新開辟一個內存,例如這樣:
引用數據類型(Object類)有常規名值對的 無序對象{a:1},數組[1,2,3],以及函數等。
當b=a進行拷貝時,其實復制的是a的引用地址,而並非堆里面的值。
b.引用數據類型--名存在棧內存中,值存在於堆內存中,但是棧內存會提供一個引用的地址指向堆內存中的值,我們以上面淺拷貝的例子畫個圖:
當b=a進行拷貝時,其實復制的是a的引用地址,而並非堆里面的值。
而當我們a[0]=1時進行數組修改時,由於a與b指向的是同一個地址,所以自然b也受了影響,這就是所謂的淺拷貝了。
那,要是在堆內存中也開辟一個新的內存專門為b存放值,就像基本類型那樣,豈不就達到深拷貝的效果了
二、實現:
- 淺拷貝:
var a = [1, 2, 3, 4, 5];
var b = a;
a[0] = 2
console.log(a);
console.log(b);
//因為b淺拷貝a, ab指向同一個內存地址(堆內存中存的值)
//b會隨着a的變化而變化
//[2, 2, 3, 4, 5]
//[2, 2, 3, 4, 5]
- 深拷貝:
1、js
function deepClone(obj){ let objClone = Array.isArray(obj)?[]:{}; if(obj && typeof obj==="object"){ for(key in obj){ if(obj.hasOwnProperty(key)){ //判斷ojb子元素是否為對象,如果是,遞歸復制
if(obj[key]&&typeof obj[key] ==="object"){ objClone[key] = deepClone(obj[key]); }else{ //如果不是,簡單復制
objClone[key] = obj[key]; } } } } return objClone; } let a=[1,2,3,4], b=deepClone(a); a[0]=2; console.log(a,b);
2、jq(深拷貝,是拷貝對象各個層級的屬性。JQ里有一個extend方法也可以拷貝對象,拷貝的不徹底啊,b對象的一級屬性確實不受影響了,但是二級屬性還是沒能拷貝成功,仍然脫離不了a的控制,說明slice根本不是真正的深拷貝。)
let a=[1,2,3,4], b=a.slice(); a[0]=2; console.log(a,b);
3、除了遞歸,我們還可以借用JSON對象的parse和stringify(附帶說下,JSON.stringify與JSON.parse除了實現深拷貝,還能結合localStorage實現對象數組存儲。)
function deepClone(obj){ let _obj = JSON.stringify(obj), objClone = JSON.parse(_obj); return objClone } let a=[0,1,[2,3],4], b=deepClone(a); a[0]=1; a[2][0]=1; console.log(a,b);
4、除了上面三種方法之外,我們還可以借用JQ的extend方法。
$.extend( [deep ], target, object1 [, objectN ] )
deep表示是否深拷貝,為true為深拷貝,為false,則為淺拷貝
target Object類型 目標對象,其他對象的成員屬性將被附加到該對象上。
object1 objectN可選。 Object類型 第一個以及第N個被合並的對象。
let a=[0,1,[2,3],4], b=$.extend(true,[],a); a[0]=1; a[2][0]=1; console.log(a,b);
三、用處:例如后台返回了一堆數據,你需要對這堆數據做操作,但多人開發情況下,你是沒辦法明確這堆數據是否有其它功能也需要使用,直接修改可能會造成隱性問題,深拷貝能幫你更安全安心的去操作數據,根據實際情況來使用深拷貝