js中的拷貝問題以及深拷貝中由於循環引用形成的死循環問題

拷貝分爲深拷貝和淺拷貝,通俗來說就是B複製了A的內容,當A進行了修改之後,看B是否變化,若是變化了就是淺拷貝,若是沒有變化就是深拷貝。javascript

淺拷貝:java

  var a = {
        key1:"111"
    }
    function copy(p){
//        console.log(p)
        var c = {};
        for(var i in p){
            c[i] = p[i];
//            console.log(i)  //  key1
        }
        return c;
    }
//    copy(a);
    a.key2 = ["you","me"];
    var b = copy(a);
    b.key3 = "ours";
    console.log(a.key3);   //  undefined
    console.log(b.key3)   //  ours
//    console.log(b)   //  {key1:"111",key2:["you","me"]}
    b.key2.push("us")
    console.log(b.key2);   //  ["you", "me", "us"]
    console.log(a.key2);   //  ["you", "me", "us"]

 

  

深拷貝:數組

第一種:遞歸深拷貝
    function deepClone(obj){
//      定義一個變量 並判斷是數組仍是對象
        var objClone = Array.isArray(obj) ? [] : {};
        if(obj && typeof obj === "object" && obj != null){ 
 // 判斷obj存在而且是對象類型的時候 由於null也是object類型,因此要單獨作判斷
            for(var key in obj){  //  循環對象類型的obj
                if(obj.hasOwnProperty(key)){  //  判斷obj中是否存在key屬性
                    if(obj[key] && typeof obj[key] === "object"){  //  判斷若是obj[key]存在而且obj[key]是對象類型的時候應該深拷貝,即在堆內存中開闢新的內存
                        objClone[key] = deepClone(obj[key]);
                    }else{  //  不然就是淺複製
                        objClone[key] = obj[key];
                    }
                }
            }
        }
        return objClone;
    }
    var a = {
        name:"key1",
        eat:[
            "蘋果",
            "香蕉"
        ]
    }
    b = deepClone(a);
//    console.log(b);
    a.eat = [
        "蘋果",
        "香蕉",
        "橙子"
    ];
    console.log(a);  //  {name:"key1",eat:["蘋果","香蕉","橙子"]}
    console.log(b)   //  {name:"key1",eat:["蘋果","香蕉"]}

遞歸運行效率低,次數過多的話容易形成棧溢出。

  

 

第二種:JSON的parse和stringify方法實現深複製
    function deepClone(obj){
//        console.log(obj);
//        console.log(typeof obj);
        var _obj = JSON.stringify(obj);  //  對象轉成字符串
//        console.log(_obj);
//        console.log(typeof _obj);
        var objClone = JSON.parse(_obj); //  字符串轉成對象
//        console.log(objClone);
//        console.log(typeof objClone);
        return objClone;
    }
    var a = [0,1,[2,3],4];
    b = deepClone(a)
    a[0] = 6;
    a[2][0] = 7;
    console.log(a);   //  [6,1,[7,3],4]
    console.log(b);   //  [0,1,[2,3],4]

  

第三種:jq的$.extend 深拷貝
    var a = [0,1,[2,3],4];
    b = $.extend(true,[],a);
    a[0] = 1;
    a[2][0] = 7;
    console.log(a);   //  [1,1,[7,3],4];
    console.log(b);   //  [0,1,[2,3],4];

$.extend參數:
第一個參數是布爾值,是否深複製
第二個參數是目標對象,其餘對象的成員屬性將被附加到該對象上
第三個及之後的參數是被合併的對象

  解決深拷貝中由於循環引用形成的死循環問題(使用數組方法)spa

function find(arr,item){
        for(var i=0; i<arr.length; i++){
            if(arr[i].source === item){
                return arr[i]
            }
        }
        return null;
    }
    function isObject(obj) {
        return typeof obj === 'object' && obj != null;
    }

    function deepClone(source,uniqueList){
        if(!isObject(source)) return source;

        if(!uniqueList) uniqueList = [];    //   初始化數據

        var target = Array.isArray(source) ? [] : {};

        var uniqueData = find(uniqueList,source);
        if(uniqueData) return uniqueData.target;


        uniqueList.push({
            source:source,
            target:target
        });

        for(var key in source){
            if(Object.prototype.hasOwnProperty.call(source,key)){
                if(isObject(source[key])){
                    target[key] = deepClone(source[key], uniqueList)      //   傳入數組
                }else{
                    target[key] = source[key];
                }
            }
        }
        return target;
    }
    var a = {
        name:"key1",
        eat:[
            "蘋果",
            "香蕉"
        ]
    }
    b = deepClone(a);
//    console.log(b);
    a.eat[2] = "桃";
    a.d = a;
    console.log(a);
    console.log(b);
相關文章
相關標籤/搜索