JavaScript-深拷貝、淺拷貝

本文檔適用于有一定經驗的開發者。我們默認你已經掌握了指針的概念(也可稱為地址) ,如果你是新手,你可能需要先了解 指針的概念

我們在JS中經常需要復制一個對象或數組。
當我們直接使用=賦值時,我們實際只賦值了這個對象的指針。這種情況 連拷貝都算不上。
例:如下我們給array2賦值,實際是賦值給array2一個指針,指針指向array1指向的數組。因此我們編輯 array2 時,array1也會變。

let array1 = [1,2,3]
let array2 = array1
array2[0] = 100
/*
 array1
>(3) [100, 2, 3]
array2
(3) [100, 2, 3]
*/

淺拷貝可以將數組(對象)的第一層拷貝下來。
ES6給我們提供了兩個方便的淺拷貝方法:
Array.from()Object.assign()
例:下面我們通過Array.from()對array3進行淺拷貝。我們可以看出,當我們修改array4的普通元素時,array3已經不會隨著改變了。但是淺拷貝只是拷貝了第一層的元素,如果第一層元素含有對象(數組),我們只拷貝一個指針(地址)。array4通過這個指針(地址)訪問的對象將是與array3是相同的。

let array3 = [1,2,3,{a:1,b:2,c:3}]
let array4 = Array.from(array3)
array4[0] = 100
array4[3].a = 100
/*
array3
>(4) [1, 2, 3, {a: 100, b: 2, c: 3}]
array4
>(4) [100, 2, 3, {a: 100, b: 2, c: 3}]
*/

目前JS常見的深拷貝有兩種方式。第一種種是兩次JSON化:
let array6 = JSON.parse(JSON.stringfiy(array5))
這種方法很簡單,但是當元素含有undefined正則表達式時函數會拋出異常。
第二種深拷貝是逐層遍歷逐一賦值的方法,要麻煩一些,但是沒有第一種的缺點。
目前,這兩種以外的拷貝方式都是淺拷貝。例如for...of遍歷中的item實際是對對象元素的淺拷貝。

// 例:逐層遍歷逐一賦值的深拷貝工具類
class deepCopy {
    static toRawType(value) {
        return Object.prototype.toString.call(value).slice(8, -1);
    }
    /* 已整合在tools中 */
    static copy(obj) {
        let emptyObject = null;
        if (this.toRawType(obj) == 'Object') {
            emptyObject = {};
        }
        else if (this.toRawType(obj) == 'Array') {
            emptyObject = [];
        }
        else {
            return obj;
        }
        for (let key in obj) {
            if (typeof obj[key] != 'object' || obj[key] == null) {
                emptyObject[key] = obj[key];
            }
            else {
                emptyObject[key] = this.copy(obj[key]);
            }
        }
        return emptyObject;
    }
}
let array5 = [1,2,3,{a:1,b:2,c:3}]
let array6  = deepCopy.copy(array5)
array6[3].a = 100
/*
array3
>(4) [1, 2, 3, {a: 1, b: 2, c: 3}]
array4
>(4) [1, 2, 3, {a: 100, b: 2, c: 3}]
*/
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。