深拷贝&浅拷贝

 

 

 

一、什么是深拷贝&浅拷贝?

浅复制:

对String类型,浅复制是对值的复制

对Object来讲,浅复制是对对象地址(引用)的复制,并没有开辟新的栈,复制的结果是原来的对象 和新的对象 指向 同一个地址 ,此时修改 一个属性的值,另一个对象的属性也会发生变化

深复制

可以理解为将原来对象的每个属性的值都拷贝过来。对于Object,深复制会开辟新的栈,新的对象和原来的对象 分别对应两个不同的地址,修改一个对象的属性,不会改变另一个对象的属性 

 

二、为什么要引入深拷贝和浅拷贝?

     引入深拷贝: 为了在改变新数组或者对象的时候,不改变原来的数据或对象。例如,在redux中必须要求reducer返回一个新的state对象,而不能对原来的state对象进行改动

 

三、浅拷贝的实现 

 

1、只复制第一层的浅拷贝

function simpleCopy(obj1) {
   var obj2 = Array.isArray(obj1) ? [] : {};
   for (let i in obj1) {
   obj2[i] = obj1[i];
  }
   return obj2;
}
var obj1 = {
   a: 1,
   b: 2,
   c: {
   d: 3
  }
}
var obj2 = simpleCopy(obj1);
obj2.a = 3;
obj2.c.d = 4;
alert(obj1.a); // 1
alert(obj2.a); // 3
alert(obj1.c.d); // 4
alert(obj2.c.d); // 4

2、Object.assign()实现浅拷贝

let obj1 = {
   a: {
     b: 1
   },
   c: 2
}
let obj2 = Object.assign({},obj1)
obj1.a.b = 3;
obj2.c = 3
console.log(obj1.a.b); // 3 console.log(obj2.a.b); // 3
console.log(obj1.c); // 2 console.log(obj2.c); // 3

四、深拷贝的实现

  此时需要考虑到,我们是只对第一层级的对象属性或数组元素进行深拷贝,还是递归拷贝所有层级的对象属性和数组元素?

 

1、for-in基本遍历实现深拷贝

 

var obj={name:'hello',age:20}

function deepCopy(obj){
    let newObj={};

    for(let item in obj){
        newObj[item]=item; //name age
    }
    
    newObj.name="qing"
    console.log(obj) //{ name: 'hello', age: 20 }
    console.log(newObj);//{ name: 'world', age: 20 }
}

 

 

function deepClone(obj1) {
        var obj2 = Array.isArray(obj1) ? [] : {};

        if (obj1 && typeof obj1 === "object") {

            for (var i in obj1) {

                var prop = obj1[i]; // 避免相互引用造成死循环,如obj1.a=obj

                if (prop == obj1) {
                    continue;
                }

                if (obj1.hasOwnProperty(i)) {

                    // 如果子属性为引用数据类型,递归复制
                    if (prop && typeof prop === "object") {
                        obj2[i] = (prop.constructor === Array) ? [] : {};
                        arguments.callee(prop, obj2[i]); // 递归调用
                    } else {

                        // 如果是基本数据类型,只是简单的复制
                        obj2[i] = prop;
                    }
                }
            }
        }
        return obj2;
    }

    let obj1={a:2,b:2};
    let obj2=deepClone(obj1);
    console.log(obj1);//{a: 2, b: 2}
    console.log(obj2);//{a: 2, b: 2}

    obj1.a=5;
    console.log(obj1);//{a: 5, b: 2}
    console.log(obj2);//{a: 2, b: 2}

3、使用JSON.stringify和JSON.parse实现深拷贝

JSON.stringify把对象转成JOSN字符串,再用JSON.parse把JSON字符串转成新的JSON对象;

var obj={name:'hello',age:20}
function deepCopy(obj){
   return JSON.parse(JSON.stringify(obj))
}
let newObj=deepCopy(obj)
newObj.name="this is the deeyCopy Object"
console.log(obj) //{ name: 'hello', age: 20 }
console.log(newObj);//{ name: 'this is the deeyCopy Object', age: 20 }

缺陷:它会抛弃对象的constructor,深拷贝之后,不管这个对象原来的构造函数是什么,在深拷贝之后都会变成Object;

           这种方法能正确处理的对象只有 Number, String, Boolean, Array, 扁平对象,也就是说,只有可以转成JSON格式的对象才可以这样用,像function没办法转成JSON;

 

因为对象的拷贝比较琐碎(复杂的类型,循环引用,函数类型等),很多库提供拷贝函数。例如以下几种:

lodash-cloneDeep  , 这是一种比较推荐的方式

AngularJS-angular.copy

jQuery-jQuery.extend(true,{},oldObject)

4、jQuery实现深拷贝

//引入jquery 
<script src="https://cdn.bootcss.com/jquery/3.2.1/jquery.js"></script>
 var myTest = {
             a: 'a',
             b: 'b'
 };
 var myTest2 = jQuery.extend(true,{}, myTest);
 myTest.b = 'b2';
 console.log(myTest2.b === 'b2');//false
参考链接:https://www.jianshu.com/p/cf1e9d7e94fb
posted @ 2019-08-17 16:11  晴之万里,温暖向西  阅读(288)  评论(0编辑  收藏  举报