美文网首页
JS 深拷贝与浅拷贝

JS 深拷贝与浅拷贝

作者: 躺在家里干活 | 来源:发表于2019-09-29 10:22 被阅读0次

    引言

    要介绍深浅拷贝那么咱们先了解一下js的数据类型。

    • 基本数据类型:number,string,boolean,undefined,null
    • 复杂数据类型:object,array,function,regexp,date 等

    一、简介

    1.浅拷贝

    对于基本数据类型,浅拷贝相当于直接赋值
    对于复杂数据类型,浅拷贝只拷贝一层,相当于只拷贝其引用,例如对象B是由对象A浅拷贝得到的,即AB还是指向内存中的同一地址,那么改变对象B,对象A也会改变

    2.深拷贝

    对于复杂数据类型,深拷贝会拷贝多层,是真正意义上的拷贝,例如对象B是由对象A深拷贝得到的,即AB指向不同的内存地址,那么无论如何改变对象B,对象A也不会改变

    二、实现方法

    上面讲完什么是深浅拷贝,那么接下来就用具体的代码去实现深浅拷贝

    1.浅拷贝

    方法一:简直粗暴的直接赋值

    var obj1 = { name: 'ming', age: 10 };
    var obj2 = obj1;
    obj2.name = 'lei';
    console.log(obj1.name) // lei
    console.log(obj2.name) // lei
    

    方法二:Object.assign(target,source) ES6

    Object.assign方法实行的是浅拷贝,而不是深拷贝。如果源对象某个属性的值是对象,那么目标对象拷贝得到的是这个对象的引用,如下面的例子

    var obj1 = { name: 'father', children: {name:'son',age:10} };
    var obj2 = Object.assign({},obj1)
    obj2.children.name = 'lei';
    console.log(obj1.children.name) // lei
    console.log(obj2.children.name) // lei
    

    方法三:for in 循环

    和方法二类似,如果源对象的某个属性是对象,那么目标对象拷贝得到的是这个对象的引用

    var obj1 = { name: 'father', children: {name:'son',age:10} };
    var obj2 = {};
    for (var key in obj1){
        obj2[key] = obj1[key];
    }
    obj2.children.name = 'lei';
    console.log(obj1.children.name) // lei
    console.log(obj2.children.name) // lei
    

    方法四:Object.create(target,source);

    Object.getOwnPropertyDescriptors 为 ES6 新增方法

    var obj1 = { name: 'father', children: {name:'son',age:10} };
    var obj2 = Object.create({}, Object.getOwnPropertyDescriptors(obj1));
    obj2.children.name = 'lei';
    console.log(obj1.children.name) // lei
    console.log(obj2.children.name) // lei
    

    2.深拷贝

    方法一:JSON.parse(JSON.stringify(source))

    用JSON.stringify将源对象(source)转为字符串,再用JSON.parse方法将字符串转为目标对象

    注: 此方法只能用作可以转为JSON格式对象,否则JSON.stringify方法将会报错,并且不管原来对象的构造函数是什么拷贝之后都会变为Object

    var obj1 = { name: 'ming', age: 10 };
    var obj2 = JSON.parse(JSON.stringify(obj1));
    obj2.name = 'lei';
    console.log(obj1.name) // ming
    console.log(obj2.name) // lei
    

    方法二:递归拷贝

    function deepClone(obj1, obj2) {
      var obj = obj2 || {};
      for (var i in obj1) {
        var temp = obj1[i]; // 避免相互引用对象导致死循环,如obj1.a = obj1的情况
        if (temp === obj) {
          continue;
        }
        if (typeof temp === 'object') {
          obj[i] = (temp.constructor === Array) ? [] : {};
          arguments.callee(temp, obj[i]);
        } else {
          obj[i] = temp;
        }
      }
      return obj;
    }
    var obj1 = { name: 'father', children: {name:'son',age:10} };
    var obj2 = deepClone(obj1);
    obj2.children.name = 'lei';
    console.log(obj1.children.name) // son
    console.log(obj2.children.name) // lei
    

    方法三:Object.create()

    function deepClone(obj1, obj2) {
      var obj = obj2 || {};
      for (var i in obj1) {
        var temp = obj1[i]; // 避免相互引用对象导致死循环,如obj1.a = obj1的情况
        if (temp === obj) {
          continue;
        }
        if (typeof temp === 'object') {
          obj[i] = (temp.constructor === Array) ? [] : Object.create(temp);
        } else {
          obj[i] = temp;
        }
      }
      return obj;
    }
    var obj1 = { name: 'father', children: {name:'son',age:10} };
    var obj2 = deepClone(obj1);
    obj2.children.name = 'lei';
    console.log(obj1.children.name) // son
    console.log(obj2.children.name) // lei
    

    方法四:Object.assign(target,source) ES6

    将源对象(source)的所有可枚举属性,复制到目标对象(target)

    注: 此方法只能用作对象只有一层的情况

    var obj1 = { name: 'ming', age: 10 };
    var obj2 = Object.assign({},obj1);
    obj2.name = 'lei';
    console.log(obj1.name) // ming
    console.log(obj2.name) // lei
    

    但是,如果源对象某个属性的值是对象,那么目标对象拷贝得到的是这个对象的引用,因此也不能被称为深拷贝

    var obj1 = { name: 'father', children: {name:'son',age:10} };
    var obj2 = Object.assign({},obj1)
    obj2.children.name = 'lei';
    console.log(obj1.children.name) // lei
    console.log(obj2.children.name) // lei
    

    方法五:for in 循环

    注: 此方法只能用作对象只有一层的情况,类似方法三

    var obj1 = { name: 'ming',age:10};
    var obj2 = {};
    for (var key in obj1){
      obj2[key] = obj1[key];
    }
    obj2.name = 'lei';
    console.log(obj1.name) // ming
    console.log(obj2.name) // lei
    

    实现浅拷贝的方法还有很多种,但是真正实现深拷贝的方法却很少,所以在拷贝对象时一定要注意

    相关文章

      网友评论

          本文标题:JS 深拷贝与浅拷贝

          本文链接:https://www.haomeiwen.com/subject/peiiyctx.html