zoukankan      html  css  js  c++  java
  • ES6中数组和对象的扩展运算符拷贝问题以及常用的深浅拷贝方法

      在ES6中新增了扩展运算符可以对数组和对象进行操作。有时候会遇到数组和对象的拷贝,可能会用到扩展运算符。那么这个扩展运算符到底是深拷贝还是浅拷贝呢?

    一.、使用扩展运算符拷贝

      首先是下面的代码。

    let a = [1,2,3];
    let b = [...a];
    a == b // false

      结果是false,这是很容易知道的,毕竟这个赋值操作符是有区别的。接下来将数组的值进行改变,又会怎样呢;

    let a = [1,2,3];
    let b = [...a];
    a[0] = 11;
    console.log(a); // [ 11, 2, 3 ]
    console.log(b); // [ 1, 2, 3 ]

      发现a的值发生改变之后b的值并没有发生改变。所以就是深拷贝了吗?别急,接下来将数组中的元素设为引用类型。

    let a = [1,2,[1,2,3]];
    let b = [...a];
    a[2][1] = 11;
    console.log(a); // [ 1, 2, [ 1, 11, 3 ] ]
    console.log(b); // [ 1, 2, [ 1, 11, 3 ] ]
    console.log(a[2] === b[2]); // true
     

      这次的结果就有意思了,如果改变数组中的引用类型的元素中的值,此时a和b的值都会改变,并且a和b中的引用类型全等,也就是说地址是相同的。那么为什么是这样的呢?

    二.、原因

      首先此分析仅为本人目前的认知。

      对于数组中的扩展运算符只是一个浅拷贝,仅对引用类型数据的第一层进行了拷贝,而倘若再深的层次就不会进行拷贝。

      另外对象的扩展运算符和数组是一样的。

    let a = {
        name : "Jyy",
        msg : {
            age : 29
        }
    }
    let b = {...a};
    console.log(a == b);    // false
    console.log(a.msg == b.msg);    // true;
    a.msg = {
        age : "28"
    }
    console.log(a); // { name: 'Jyy', msg: { age: '28' } }
    console.log(b); // { name: 'Jyy', msg: { age: 29 } }

    三、深拷贝和浅拷贝的方法

      1.浅拷贝方法

        上面的例子已经看出来es6中的扩展运算符仅仅对引用类型进行了第一层的拷贝。除了es6的扩展运算符还有其他方法

        对象:

          使用Object.assign()

            Object.assign()用于对象的合并,如果第一个参数为{},则可对后面的对象参数进行拷贝

    let a = {
        name : "Jyy",
        msg : {
            age : 29
        }
    }
    let b = Object.assign({},a);
    console.log(a == b);    // false
    console.log(a.msg == b.msg);    // true;
    a.msg = {
        age : "28"
    }
    console.log(a); // { name: 'Jyy', msg: { age: '28' } }
    console.log(b); // { name: 'Jyy', msg: { age: 29 } }

        数组: 

          数组的浅拷贝的方法很多

          a.使用slice()

            slice可以截取数组中部分的元素,若参数为空,则可对数组进行浅拷贝

    let a = [1,2,[1,2,3]];
    let b = a.slice();
    console.log(a == b);    // false
    a[2][1] = 11;
    a[0] = 11;
    console.log(a); // [ 11, 2, [ 1, 11, 3 ] ]
    console.log(b); // [ 1, 2, [ 1, 11, 3 ] ]
    console.log(a[2] == b[2]);  // true

          b.使用concat()

            concat可以对数组进行合并,若参数为空,亦可对数组进行浅拷贝

    let a = [1,2,[1,2,3]];
    let b = a.concat();
    console.log(a == b);    // false
    a[2][1] = 11;
    a[0] = 11;
    console.log(a); // [ 11, 2, [ 1, 11, 3 ] ]
    console.log(b); // [ 1, 2, [ 1, 11, 3 ] ]
    console.log(a[2] == b[2]);  // true

          c.使用Array.from()

    let a = [1,2,[1,2,3]];
    let b = Array.from(a);
    console.log(a == b);    // false
    a[2][1] = 11;
    a[0] = 11;
    console.log(a); // [ 11, 2, [ 1, 11, 3 ] ]
    console.log(b); // [ 1, 2, [ 1, 11, 3 ] ]
    console.log(a[2] == b[2]);  // true

      2.深拷贝

        对于深拷贝,数组和对象的方法是一致的

        a.递归方法,就是用for循环一层一层的进行拷贝,具体代码就不写了

        b.JSON.parse()

          这个方法通常用于调用接口传参或者是返回的字符串数据转成对象。

    let a = {
        name : "JYY",
        age : "25",
        msg : {
            addr : "hebei"
        }
    }
    b = JSON.parse(JSON.stringify(a));
    console.log(a == b);    // false
    console.log(a.msg == b.msg);    // false
    a.msg.addr = "chengde";
    console.log(a); // { name: 'JYY', age: '25', msg: { addr: 'chengde' } }
    console.log(b); // { name: 'JYY', age: '25', msg: { addr: 'hebei' } }

          这个方法的弊端就是undefinedfunctionsymbol 会在转换过程中被忽略

    let a = {
        name : "JYY",
        age : "25",
        msg : {
            addr : "hebei"
        },
        speek : function(){
            console.log(this.name);
        }
    }
    b = JSON.parse(JSON.stringify(a));
    console.log(a); // { name: 'JYY', height: Symbol(jyy), age: undefined, msg: { addr: 'chengde' },speek: [Function: speek] }
    console.log(b); // { name: 'JYY', msg: { addr: 'hebei' } }

        c.使用第三方插件

          比如lodash的深拷贝

    const _ = require("lodash");
    let syb = Symbol('jyy');
    let a = {
        name : "JYY",
        height: syb,
        age : undefined,
        msg : {
            addr : "hebei"
        },
        speek : function(){
            console.log(this.name);
        }
    }
    let b = _.cloneDeep(a);
    console.log(a == b);    // false
    console.log(a.msg == b.msg);    // false
    console.log(a); // { name: 'JYY', height: Symbol(jyy), age: undefined, msg: { addr: 'chengde' },speek: [Function: speek] }
    console.log(b); // { name: 'JYY', height: Symbol(jyy), age: undefined, msg: { addr: 'chengde' },speek: [Function: speek] }
  • 相关阅读:
    文件的增删改查
    集合的使用
    字典的使用
    字符串常用操作
    简单购物车程序练习题
    列表
    数据运算数据类型与
    模块初识
    数据库时间设置
    ubuntu 修改时区
  • 原文地址:https://www.cnblogs.com/jyybeam/p/11831298.html
Copyright © 2011-2022 走看看