JS的深淺複製,原來如此!
阿新 • • 發佈:2021-10-13
摘要:之所以會出現深淺拷貝的問題,實質上是由於JS對基本型別和引用型別的處理不同。
本文分享自華為雲社群《js的深淺複製,一看就明白》,作者: 鑫2020。
淺複製的意思
淺複製是僅僅對資料存放在棧內的引用的複製,沒有複製引用指向堆內的內容。多個數據的淺複製,這複製多個引用,這多個引用共同指向堆內的同一個內容。當一個淺複製資料做出修改,即堆內的引用指向的內容發生修改,這時,其他通過引用指向這裡的資料也會隨著改變。
let obj = { a:1, b:2, c:{ c1:10, c2:20 } } let objA = obj; objA.a= 'a'; console.log(obj.a); // 'a' console.log(objA.a); // 'a'
深複製的意思
深複製是指連同堆的內容一塊複製,生成一個新的物件。多個深複製將是多個不同的物件,也就有不同的引用,也就指向不同的堆內容。
使用深複製的原由
在平常開發中,有時會有資料的傳遞與接收,當拿到傳過來的資料後,難免需要對資料進行加工和改造,為了不破壞原有資料結構,這時就可以使用深複製拷貝資料,然後處理生成的新的資料。深複製也可以防止修改多個引用後引用混亂的問題,減少BUG的產生機會。
可實現深複製的幾種方法
實現方式一:JSON的序列化與反序列化
let obj = { a:1, b:2, c:{ c1:10, c2:20 } } let objA = JSON.parse(JSON.stringify(obj));//JSON的序列化與反序列化 objA.a = 'a'; console.log(obj.a); // 1 console.log(objA.a); // 'a'
雖然JSON的序列化與反序列化可以實現深複製,但有幾個缺點需要注意:
1、date日期物件被轉成日期日期字串
2、沒法訪問到原型
3、複製不了undefined的屬性
4、NAN和無窮被轉為NULL
let d1 = new Date(); let obj= { d1, d2: undefined, d3:NaN } let objD = JSON.parse(JSON.stringify(obj)); console.log(obj) console.log(objD)
實現方式二:Object.assign()
let obj = { a:1, b:2, c:{ c1:10, c2:20 } } let objA = Object.assign(obj); objA.a = 'a'; console.log(obj.a); // 1 console.log(objA.a); // 'a'
雖然Object.assign()可以實現深複製,但對於更深層次的物件引用也是僅僅淺複製。
let obj = { a:1, b:2, c:{ c1:10, c2:20 } } let objA = Object.assign(obj); objA.c.c1 = 'c1'; //Object.assign()僅僅是一層深複製。 console.log(obj.c.c1); // 'c1' console.log(objA.c.c1); // 'c1'
實現方式三:擴充套件運算子
let obj = { a:1, b:2, c:{ c1:10, c2:20 } } let objA = {...obj};; objA.a = 'a'; console.log(obj.a); // 1 console.log(objA.a); // 'a'
雖然擴充套件運算子"…"可以實現深複製,但對於更深層次的物件引用也是僅僅淺複製。
let obj = { a:1, b:2, c:{ c1:10, c2:20 } } let objA = {...obj}; objA.c.c1 = 'c1'; //擴充套件運算子"..."同Object.assign()一樣,僅僅是一層深複製,不能多層深複製。 console.log(obj.c.c1); // 'c1' console.log(objA.c.c1); // 'c1'
實現方式四:使用遞迴
想要實現深複製,且實現多層深複製則可以使用遞迴迴圈複製。
let obj = { a:1, b:2, c:{ c1:10, c2:20 } } const ReCopy = function (paramter) { let target = null; let isObject = paramter.constructor === Object; let isArray = paramter.constructor === Array; if (isObject || isArray) { target = Array.isArray(paramter) ? [] : {}; for (let i in paramter) { target[i] = ReCopy(paramter[i]); } } else { target = paramter; } return target; } let objA = ReCopy(obj); objA.c.c1 = 'c1'; console.log(obj.c.c1); // 10 console.log(objA.c.c1); // 'c1'
ladash深拷貝
lodash深複製是更專業的深複製方式。
- 安裝lodash
先初始化,生成package.json檔案,然後使用一下命令安裝。
npm i -S lodash
- 引入lodash
var _ = require('lodash');
- 使用lodash
let obj = { a:1, b:2, c:{ c1:10, c2:20 } } let objA = _.cloneDeep(obj); objA.c.c1 = 'c1'; console.log(obj.c.c1); // 10 console.log(objA.c.c1); // 'c1'