1. 程式人生 > 其它 >一篇搞懂深拷貝和淺拷貝

一篇搞懂深拷貝和淺拷貝

技術標籤:前端開發jsjavascript

1.定義

深拷貝和淺拷貝最根本的區別在於是否真正獲取一個物件的複製實體,而不是引用。假設B複製了A,修改A的時候,看B是否發生變化:如果B跟著也變了,說明是淺拷貝(修改了堆記憶體中的同一個值)如果B沒有改變,說明是深拷貝(修改了堆記憶體中的不同的值)

2.區別

  • 淺拷貝(shallowCopy) 只是增加了一個指標指向已存在的記憶體地址,僅僅是指向被複制的記憶體地址,如果原地址發生改變,那麼淺複製出來的物件也會相應的改變。
  • 深拷貝(deepCopy) 是增加了一個指標並且申請了一個新的記憶體,使這個增加的指標指向這個新的記憶體。 在計算機中開闢一塊新的記憶體地址用於存放複製的物件。

3.例項

  • 淺拷貝實現:
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]

如圖所示:a、b指向同一堆記憶體地址
在這裡插入圖片描述
淺複製只複製一層物件的屬性,而深複製則遞迴複製了所有層級。

var obj = { a:1, arr: [2,3] };
var shallowObj = shallowCopy(obj);

function shallowCopy
(src) { var dst = {}; for (var prop in src) { if (src.hasOwnProperty(prop)) { dst[prop] = src[prop]; } } return dst; } // 導致的結果就是: shallowObj.arr[1] = 5; obj.arr[1] // = 5
  • 深拷貝實現:
    (1) js遞迴
// 初始物件資料
var a = {
          a:1,
          arr: [1,2],
          nation : '中國',
          birthplaces:
['北京','上海','廣州'] }; // 採用遞迴方式封裝深拷貝方法deepCopy function deepCopy(obj) { // 首先新增拷貝變數並根據判斷引數資料型別來確定拷貝變數資料型別是物件還是陣列 var newObj = obj instanceof Array ? [] : {}; if(typeof obj !== 'object'){ return obj }else{ for (var i in obj) { newObj[i] = typeof obj[i] === 'object' ? deepCopy(obj[i]) : obj[i]; } } return newObj } // 把a拷貝成b var b = deepCopy(a) // 改變原來a物件中的任一屬性的值 a.nation = '北京'; // 列印後資料對比 console.log(a,'修改後的a資料') console.log(b,'深拷貝後的b資料')

列印結果: 原物件a被修改內部屬性值後資料發生了改變,而深拷貝後的b資料保持不變,即b物件並沒有因為a物件的改變而改變,因為b深拷貝a
在這裡插入圖片描述
(2)除了遞迴,我們還可以借用JSON物件的parse和stringify(附帶說下,JSON.stringify與JSON.parse除了實現深拷貝,還能結合localStorage實現物件陣列儲存。)

function deepCopy(obj){
    let _obj = JSON.stringify(obj),
        objClone = JSON.parse(_obj);
    return objClone
}    
let a=[0,1,[2,3],4],
    b=deepCopy(a);
a[0]=1;
a[2][0]=1;
console.log(a,b);

在這裡插入圖片描述
3)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);

在這裡插入圖片描述

4.使用場景

例如後臺返回了一堆資料,你需要對這堆資料做操作,但多人開發情況下,你是沒辦法明確這堆資料是否有其它功能也需要使用,直接修改可能會造成隱性問題,深拷貝能幫你更安全安心的去操作資料,根據實際情況來使用深拷貝;

需要注意的是,如果物件比較大,層級也比較多,深複製會帶來效能上的問題。在遇到需要採用深複製的場景時,可以考慮有沒有其他替代的方案。在實際的應用場景中,也是淺複製更為常用