ES6对象展开运算符&&浅拷贝or深拷贝


ES6中提出的对象展开运算符”…“就是用来展开元素的。有了它就不用代码循环遍历了,偷懒专用。

  1. 合并数组

    展开原有数组中的所有元素,可以合并成一个新的数组

    var a=[1,2,3];
    var b=[4,5,6];
    var c=[...a,...b];
    console.log(c) // 输出:[1, 2, 3, 4, 5, 6]
  2. 合并对象

    展开对象中的所有属性,可以合并成一个新的对象

    var person1 = {
      name: '小明',
      age: 18,
      sex: '男',
    }
    var hobby = {
      music: '伤感类歌曲',
      like: '吃饭、睡觉、打游戏',
    }
    var xiaoMing = {...person1,...hobby}
    console.log(xiaoMing)
    // 输出:{name: "小明", age: 18, sex: "男", music: "伤感类歌曲", like: "吃饭、睡觉、打游戏"}
  3. 合并对象并修改属性

    修改对象其实也是合并对象,只不过是:当几个对象中含有同名参数时,后面的会把前面同名属性值覆盖掉。

    var person1 = {
      name: '小明',
      age: 18,
      sex: '男',
    }
    var hobby = {
      music: '伤感类歌曲',
      like: '吃饭、睡觉、打游戏',
    }
    var xiaoHong = {
      ...person1,
      ...{name: '小红',sex:'女'},
      ...hobby
    }
    console.log(xiaoHong)
    // 输出:{name: "小红", age: 18, sex: "女", music: "伤感类歌曲", like: "吃饭、睡觉、打游戏"}
  1. 对象展开运算符是浅拷贝还是深拷贝?

    先来了解下,浅拷贝和深拷贝各自的含义:

    数据可以分为两大类:一类是基本数据,一类是引用数据;而数据存储位置又可分为栈和堆。

    基本数据是存储在栈中的,深拷贝和浅拷贝操作的都是真实的数据,所以没有区别。

    故而,深拷贝和浅拷贝主要是针对引用数据来说的。

    引用数据,相当于是在栈中存储了一个地址,这个地址指向堆中的真实数据,

    浅拷贝,相当于把栈中的地址给了一个新的对象,新对象和旧对象指向的都是堆中同一个数据,所以无论哪个对象发生变化都会影响堆中的这个数据;

    深拷贝,是在堆中重新开辟一片空间,生成了一个新的数据区域,这样新对象指向的是新的数据,旧对象指向的是旧的数据,所以这两个数据区无论谁发生变化都不会影响另一个。

    下面看一个浅拷贝的例子:

    var person1 = {
      name: '小明',
      age: 18,
      sex: '男',
    }
    
    var xiaoHong = person1; // 这里只是将引用变量person1给了xiaoHong
    xiaoHong.name = '小红';
    
    console.log(person1) // 输出:{name: "小红", age: 18, sex: "男"}
    console.log(xiaoHong)// 输出:{name: "小红", age: 18, sex: "男"}

    由上面的例子,很清楚的看到:当xiaoHong的name属性值变化了之后,person1的name属性值也发生变化了,所以两个对象指向的是同一个数据区域,是浅拷贝。

    那么对象展开运算符是浅拷贝还是深拷贝呢?看下面例子:

    var person1 = {
      name: '小明',
      age: 18,
      sex: '男',
    }
    
    var xiaoHong = {...person1}
    xiaoHong.name = '小红';
    
    console.log(person1) // 输出: {name: "小明", age: 18, sex: "男"}
    console.log(xiaoHong)// 输出: {name: "小红", age: 18, sex: "男"}

    哎,用对象展开符的xiaoHong的name属性变化了之后,person1的name属性没有变化呀!难道对象扩展符是深拷贝?别急,往下看。

    再看下面的例子,对象中包含着第二层数据对象。

    var person1 = {
      name: '小明',
      age: 18,
      sex: '男',
      hobby: {
        music: '伤感类歌曲',
        like: '吃饭、睡觉、打游戏',
      }
    }
    
    var xiaoHong = {...person1}
    xiaoHong.name = '小红';
    xiaoHong.hobby.music = '小清新歌曲';
    
    console.log(person1)
    // 输出: {name: "小明", age: 18, sex: "男", hobby: {music: "小清新歌曲",like: "吃饭、睡觉、打游戏"}}
    console.log(xiaoHong)
    // 输出: {name: "小红", age: 18, sex: "男", hobby: {music: "小清新歌曲",like: "吃饭、睡觉、打游戏"}}

    看上面代码片段,对比新旧两个对象的输出:

你发现对象展开运算符并不是深拷贝,而是浅拷贝。

我感觉可以这么理解:对象展开预算符相当于展开遍历了对象的第一层数据,第一层数据如果是基本数据,就是简单的值;第一层数据若是引用数据,就是浅拷贝。


文章作者: 木华
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 木华 !
评论