淺拷貝與深拷貝的實現方案與應用場景


寫在前面

首先我們得清楚基本概念。拷貝(Copy)即復制。

淺拷貝:創建一個新對象,保存原始對象屬性值精准拷貝。如果屬性是基本類型,拷貝的是基本類型的值,如果屬性是引用類型,拷貝的是內存地址,並不會占用新的內存,這種情況下如果其中一個對象改變了這個地址,會影響到另一個對象。淺拷貝只復制指向某個對象的指針,而不復制對象本身。新舊對象共享同一塊內存

深拷貝:將一個對象從內存中完整的拷貝一份出來,從堆內存中開辟一個新的區域存放新對象,增加了內存,且修改新對象不會影響原對象。新對象與原對象不共享內存

賦值和深/淺拷貝的區別(針對引用類型)

賦值:把一個對象賦值給一個新的變量時,賦的其實是該對象的在棧中的地址,而不是堆中的數據。

淺拷貝:重新在堆中創建內存,拷貝前后對象的基本數據類型互不影響,但拷貝前后對象的引用類型因共享同一塊內存,會相互影響。

深拷貝:從堆內存中開辟一個新的區域存放新對象,對對象中的子對象進行遞歸拷貝,前后的兩個對象互不影響。

淺拷貝的實現方案

0x01 Object.assign()

把任意多個源對象自身的可枚舉屬性拷貝給目標對象,然后返回目標對象。

let obj2 = Object.assign({}, obj1)

0x02 函數庫lodash的_.clone方法

var _ = require('lodash');

var obj2 = _.clone(obj1);

0x03 展開運算符

同object.assign()功能相同

let obj2 = {...obj1}

0x04 Array.prototype.concat()

let arr2 = arr1.concat() // 返回新數組,但當數組中嵌套數組對象時為淺拷貝

0x05 Array.prototype.slice()

let arr2 = arr1.slice() // 返回新數組,但當數組中嵌套數組對象時為淺拷貝

深拷貝的實現方案

0x01 JSON.parse()和JSON.stringify()

let arr2 = JSON.parse(JSON.stringify(arr1));

缺點是不能處理函數和正則

0x02 函數庫lodash的_.cloneDeep方法

var _ = require('lodash');

var obj2 = _.cloneDeep(obj1);

0x03 jQuery.extend()方法

$.extend(deepCopy,target,obj1,[objN]) // 第一個參數為true就是深拷貝

0x04 手寫遞歸實現

解決循環引用的問題

function deepClone(obj, hash=new WeakMap()) {
  if(obj == null) return obj; // 不操作
  if(obj instanceof Date) return new Date(obj);
  if(obj instanceof RegExp) return new RegExp(obj);
  // 普通值/函數不需要深拷貝
  if(typeof obj !== "object") return obj;
  // 是對象的話要進行深拷貝
  if(hash.get(obj)) return hash.get(obj);
  let cloneObj = new obj.constructor();
  // 找到的是所屬類原型上的constructor,而原型上的constructor指向的是當前類本身
  hash.set(obj. cloneObj);
  for(let key in obj) {
    if(obj.hasOwnProperty(key)) {
      cloneObj[key] = deepClone(obj[key], hash)
    }
  }
  return cloneObj;
}

深拷貝與淺拷貝的應用場景

無論是淺拷貝還是深拷貝,一般都用於操作Object 或 Array之類的復合類型。

比如想對某個數組 或 對象的值進行修改,但是又要保留原來數組 或 對象的值不被修改,此時就可以用深拷貝來創建一個新的數組 或 對象,從而達到操作(修改)新的數組 或 對象時,保留原來數組 或 對象。

場景:從服務器fetch到數據之后我將其存放在store中,通過props傳遞給界面,然后我需要對這堆數據進行修改,那涉及到的修改就一定有保存和取消,所以我們需要將這堆數據拷貝到其它地方。

在JS中有一些已經封裝好的如數組方法:concat(),filter(),slice(),map()等,在修改數組時,不會修改原來的數組,而是返回一個新的數組。但這並不是真正的深拷貝,當數組中嵌套數組對象時仍為淺拷貝,嵌套數組的改變仍會影響原數組的值。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM