1. 程式人生 > 其它 >物件、陣列、函式等多種資料型別的深淺克隆(拷貝)

物件、陣列、函式等多種資料型別的深淺克隆(拷貝)

物件(陣列)的深淺克隆

淺克隆

obj{ }物件裡面的所有屬性拷貝到obj1{ }中後,然後分別改變物件裡面的變數,原始值互不影響,引用值一個改變,另一個跟著變。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script>
        // 淺克隆
        // a、d 原始值; b、c 引用值
        let obj = {
            a: 100,
            b: [10, 20, 30],
            c: {
                x: 10
            },
            d: /^\d+$/
        };

        // let obj2 = {...obj};

        let obj2 = {};
        for (let key in obj) {
            if (!obj.hasOwnProperty(key)) break;
            obj2[key] = obj[key];
        }
        console.log(obj);   //  { a: 100, b: (3) [10, 20, 30], c: {x: 10}, d: /^\d+$/ }
        console.log(obj2);  //  { a: 100, b: (3) [10, 20, 30], c: {x: 10}, d: /^\d+$/ }

        obj2.a = 200;
        obj2.b[0] = 55;
        obj2.c["x"] = 66;
        obj2.d = /^\d-$/;

        console.log(obj);   //  { a: 100, b: (3) [55, 20, 30], c: {x: 66}, d: /^\d+$/ }
        console.log(obj2);  //  { a: 200, b: (3) [55, 20, 30], c: {x: 66}, d: /^\d-$/ }
    </script>
</body>
</html>

深克隆

修改引用值時,互不影響,你改我不變

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script>
        // 深克隆
        let obj = {
            a: 100,
            b: [10, 20, 30],
            c: {
                x: 10
            },
            d: /^\d+$/,
            e : function() {
                return 50;
            },
            f: new Date(),
            g: new Map([["a", 1], ["b", 2], ["c", 3]]),
            h: new Set([1, 2, 3, 3, 4, {a : 10}]),
            i: null,
            j: undefined
        };

        // 先轉為字串再轉回物件的過程會重新開闢記憶體空間
        //  日期,函式,正則在轉為字串時會出現問題
        // 函式(不輸出),正則(輸出空物件),時間物件(輸出時間字串),Undefiend(不輸出)
        let obj2 = JSON.parse(JSON.stringify(obj));  
        obj2.b[0] = 22;
        console.log(obj);   //  { a: 100, b: (3) [10, 20, 30], c: {x: 10}, d: /^\d+$/, e: ƒ e() }
        console.log(obj2);  //  { a: 100, b: (3) [22, 20, 30], c: {x: 10}, d: {}, [[Prototype]]: Object }

        function deepClone(obj) {
            // 處理null
            if (obj === null) return null;
            // 處理原始值
            if (typeof obj  != "object" && typeof obj != "function") return obj;
            // 處理函式
            if (typeof obj === "function") {
                let func = obj + ''
                // 返回匿名函式
                // new Function('...')()  直接執行引號中的內容,與eval
                return new Function('return ' + func)();
            }
            // 處理正則
            if (obj instanceof RegExp) {
                return new RegExp(obj);
            }
            // 處理Set物件
            if (obj instanceof Set) {
                return new Set(obj);
            }
            // 處理Map物件
            if (obj instanceof Map) {
                return new Map(obj);
            }
            // 處理日期
            if (obj instanceof Date) {
                return new Date(obj);
            }
            // 用被克隆物件的建構函式建立一個例項,這樣克隆出來的物件也是那個建構函式的例項,保持相同的所屬類
            let newObj = new obj.constructor;
            for (let key in obj) {
                if (obj.hasOwnProperty(key)) {
                    newObj[key] = deepClone(obj[key]);
                }
            }

            return newObj;
        }
        let obj3 = deepClone(obj);
        console.log(obj);   //  { a: 100, b: (3) [10, 20, 30], c: {x: 10}, d: /^\d+$/, e: ƒ e() }
        console.log(obj3);  //  { a: 100, b: (3) [10, 20, 30], c: {x: 10}, d: /^\d+$/, e: ƒ e() }
        console.log(obj === obj3);      //  false
        console.log(obj.c === obj3.a);  //  false
        console.log(obj.e === obj3.b);  //  false
        console.log(obj.e === obj3.c);  //  false
        console.log(obj.e === obj3.d);  //  false
        console.log(obj.e === obj3.e);  //  false
        console.log(obj.e === obj3.f);  //  false
        console.log(obj.e === obj3.g);  //  false
        console.log(obj.e === obj3.h);  //  false
        console.log(obj.e === obj3.i);  //  false
        console.log(obj.e === obj3.j);  //  false
    </script>
</body>
</html>