深複製

mengyuhang4879發表於2020-12-17

淺複製

學深複製之前我們先了解一下淺複製
image.png
可以看到使用擴充套件運算子進行複製obj之後生成objCopy,改變objCopy的值obj的值並沒有跟著變化。這麼看是沒有任何問題,那麼我們再來嘗試下將obj.a變成一個陣列呢。
image.png
上面可以看到兩個物件變成了一樣的,由此可以得出淺複製只能複製一層。

深複製

1 JSON.parse(JSON.stringify())

這種深複製方式會有幾個問題,讓我們來看一下。

  • 1 時間和正則的問題

使用這個方法執行後時間格式會變成字串格式(正則同理)
image.png

  • 2 丟失和型別

使用序列化之後會導致函式丟失,obj裡有NaN、Infinity和-Infinity,則序列化的結果會變成null
image.png

自己實現一個深複製

/*
* 資料型別:基本資料型別,引用資料型別;
* 基本資料型別:String,null,undefined,Number,Boolean
* 引用資料型別:RegExp,Date,Array,object,Function
* */
function deepClone(value) {
    //判斷是否為null/undefined,因為在不是===的情況下 null=undefined if (value == undefined) return;
    //判斷是否是正則
 if (value instanceof RegExp) return new RegExp(value);
    //判斷是否是時間格式
 if (value instanceof Date) return new Date(value);
    //判斷是否是String,Number,Boolean,Function(因為函式不會進行複製,直接執行)
 if (typeof value != 'object') return value;
    // 能走到這裡的只有陣列和物件了
 //value.constructor指向建構函式本身 Array/Object. new Array/new Object生成的就是[]/{}
 let container = new value.constructor;
    for (let key in value) {
        container[key] = deepClone(value[key])
    }
    return container
}
let obj = {
    a: [1, 2],
    b: 500
};
let objCopy = deepClone(obj);
obj.a[0]=100;
console.log('我是obj', obj);
console.log('我是objCopy', objCopy);

上面基本實現了一個深複製,但是在這個方法中還存在些問題。如果我傳入這樣一個物件那麼就會出現爆棧的現象。

let b={};
let a = {b:b};
b.a=a;
let copy = deepClone(a);
console.log(copy);

瀏覽器報錯:
image.png

這個方法顯然不是很友好,那麼我們使用Map和Set函式來最佳化一下,如果在Map中能找到直接使用Map中的即可;
完整程式碼:

/*
* 資料型別:基本資料型別,引用資料型別;
* 基本資料型別:String,null,undefined,Number,Boolean
* 引用資料型別:RegExp,Date,Array,object,Function
* */
//傳入map
function deepClone(value, hash = new Map()) {
    //判斷是否為null/undefined,因為在不是===的情況下 null=undefined if (value == undefined) return;
    //判斷是否是正則
 if (value instanceof RegExp) return new RegExp(value);
    //判斷是否是時間格式
 if (value instanceof Date) return new Date(value);
    //判斷是否是String,Number,Boolean,Function(因為函式不會進行複製,直接執行)
 if (typeof value != 'object') return value;
    //進來先判斷是不是在map中,如果存在直接獲取,就不需要再執行下面的deepClone函式進行遞迴為瀏覽器開闢無數個新的記憶體了。
 if (hash.get(value)) {
        return value;
    }
    // 能走到這裡的只有陣列和物件了
 //value.constructor指向建構函式本身 Array/Object. new Array/new Object生成的就是[]/{}
 let container = new value.constructor;
    //每次進來向map函式中存值
 hash.set(value, container)
    for (let key in value) {
        container[key] = deepClone(value[key], hash)
    }
    return container
}
let b = {};
let a = {b: b};
b.a = a;
let copy = deepClone(a);
console.log(copy);

輸出結果
image.png

相關文章