js中的拷贝问题以及深拷贝中因为循环引用造成的死循环问题

拷贝分为深拷贝和浅拷贝,通俗来讲就是B复制了A的内容,当A进行了修改以后,看B是否变化,如果变化了就是浅拷贝,如果没有变化就是深拷贝。

浅拷贝:

  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参数:
第一个参数是布尔值,是否深复制
第二个参数是目标对象,其他对象的成员属性将被附加到该对象上
第三个及以后的参数是被合并的对象

  解决深拷贝中因为循环引用造成的死循环问题(使用数组方法)

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);

  

原文地址:https://www.cnblogs.com/ly-qingqiu/p/10881801.html