遞歸實現深拷貝( 只要學過js遞歸,看不懂找我包會 )


要用遞歸實現深拷貝,首先說說什么是深拷貝和淺拷貝

淺拷貝:一個值賦給另一個值,當原先的值不改變地址的情況下改變數據,另一個值跟着變
深拷貝:一個值賦給另一個值,當原先的值不改變地址的情況下改變數據,另一個值不變
 
注意 : 強調一點,原先的值不改變地址的情況下改變數據,如果是改了地址的改變,那將用另一個值的改變與否判斷深拷貝淺拷貝毫無意義
 
// 舉一個簡單的例子---以下的obj,obj2可以看做是這里的obj,obj2

var obj = {
    name : 'zs',  
    age : 18  
}
// 淺拷貝 var obj2 = obj;
obj.name = 'ls';
console.log(obj2) // { name : 'ls' , age : 18  }

這是淺拷貝,單單就是把obj的地址給了obj2,obj改了,obj2也要改。再來說說這obj改了,這里面有點不同。要么 obj改了屬性(數組就是改了元素),要么干脆obj指向另一個地址,例如:obj = 1;針對第一種就是深淺拷貝可以作為判斷依據的,根據改了之后obj2改不改就可以看出深拷貝(不改)還是淺拷貝(改了)。第二種不管深淺拷貝的因為obj的地址變了,obj再怎么改都不會影響obj2,因此obj2肯定不會變,深淺拷貝看不出來的

var obj = {
    name : 'zs',  
    age : 18  
}
var obj2 = obj;
// obj 自己地址都變了,再怎么折騰影響不了obj2了
obj = 1;
console.log(obj2) // { name : 'zs' , age : 18  }

//  以上 obj可以看做第一個對象(數組) ,obj2 可以看做第二個對象(數組) ,為什么不說函數呢? 因為函數本身辦法改內容,聲明的時候已經確定好函數體了,你還能有神通在不改變聲明函數的函數體前提下,后續添加函數體語句?如果可以,請教教我,說真的!

----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

以下重點說說深拷貝 : 說白了深拷貝的目的就是不想讓obj來影響obj2,有點過河拆橋的意思,把好處或愛情給了另一個人,另一個人卻不想讓你打擾她(說多了是淚)

針對以下三種常見情況提供三種方式進行深拷貝 : 

很純的對象 : 屬性值沒有數組、對象的   var obj2 = Object.assgin({ }, obj)

沒有方法的對象 (沒有方法在內,可以有數組和對象充當屬性值) : var obj2 = JSON.parse(JSON.stringify(obj)) 

        var u = {
            o : {'name' : 'zs'},
            i : 5
        }
        var v = JSON.parse(JSON.stringify(u))
        u.o.name = 'ls';
        console.log(u,v);  // v的o屬性中的name還是'zs'

③ 遞歸( 通用,從底層的角度 ) 基本思想 : 判斷obj 是基本類型就簡單賦值,對象(數組)的話 ,創建一個空[ ](obj是對象)或空{ }(obj是對象),再判斷obj的屬性有沒有對象(數組),有遞歸調用,沒有簡單賦值,直到全部賦值完畢,返回賦值后的new_obj , 看不懂沒關系下面代碼有注釋,絕對可以看懂

var obj = {
            arr1 : [1,2,3],
            fn: function(){
                console.log('我是一個方法')
            },
            a : '我是普通屬性'
        }
        
        // 現在我要把obj字面量創建里的屬性深拷貝( 屬性值是引用類型也要深拷貝 )
        function deepClone(obj){
            // 根據類型制造一個新的數組或對象 => 指向一個新的空間
                // 由於數組的typeof也是'object',所以用Array.isArray(obj)
            var new_obj = Array.isArray(obj) ? [] : {};
            // 首先判斷obj的類型
                // 普通類型
            if( typeof obj != 'object' ){
                // 這里不能直接返回obj,不然就是淺拷貝的性質
                return  new_obj = obj
            }
                //引用類型
                    //數組
            if(obj instanceof Array ){
                for(i = 0; i < obj.length; i++ ){
                    new_obj[i] = obj[i];
                    if(typeof new_obj[i] == 'object'){
                        deepClone(new_obj[i])
                    }
                }
            }else{ //對象
                for (let key in obj) {
                    if (obj.hasOwnProperty(key)) {
                        // 對象中的數組和對象
                        if (typeof obj[key] == 'object') {
                            new_obj[key] = deepClone(obj[key]); 
                        }else{//對象中沒有引用類型
                            new_obj[key] = obj[key]
                        }  
                    }
                }
            }
            return new_obj;
        }
        var deepClone = deepClone(obj);
        console.log(deepClone);
        // 測試是不是深拷貝
        obj.fn = '我改變了方法屬性';
        console.log(obj); //{arr1: Array(3), fn: ƒ, a: "我是普通屬性", c: "我新增了一個屬性"}
        console.log(deepClone); // 還是 {arr1: Array(3), fn: ƒ, a: "我是普通屬性"}

-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

本文原創,僅供學習使用


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM