1. 程式人生 > 其它 >JS的深淺複製,原來如此!

JS的深淺複製,原來如此!

摘要:之所以會出現深淺拷貝的問題,實質上是由於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'

點選關注,第一時間瞭解華為雲新鮮技術~