ES6笔记 - 扩展运算符

扩展运算符

1. 数组中的扩展运算符

  • 扩展运算符...可以将一个数组转换为用逗号分隔的参数序列,一定程度上取代了apply()

    只要是实现了Iterator接口的对象,都可以使用扩展运算符拆分

    console.log(...[1,2,3]);	//1,2,3
    console.log(0,...[1,2,3],4);	//0,1,2,3,4
    
    var numbers = [4,38];
    add(...numbers); //42
    
  • 扩展运算符可以与正常函数参数结合使用

    function(v,w,x,y,z){}
    var args = [0,1];
    f(-1,...args,2,...[3]);
    
  • 扩展运算符后面还可以放置表达式

    const arr = [...(x > 0 ? ['a'] : []),b];
    

1.1 应用场景

  • 合并数组

    var arr1 = ['a','b']
    var arr2 = ['c']
    
    var arr = [...arr1, ...arr2]
    
  • 字符串拆分

    [...'hello']
    //["h","e","l","l","o"]
    
  • 读取函数返回值

    //取出数组形式的数据
    var dateFields = readDateFields(database);
    //扩展运算符直接拆分数组传参
    var d = new Date(...dateFields);
    

2. 对象中的扩展运算符

  • 扩展运算符...也可以用于取出参数对象中的所有可遍历属性,并将其复制到当前对象之中

    let z = {a:3, b:4};
    let n = {...z}	//{a:3, b:4}
    

2.1 应用场景

  • 拆分对象

    //取出对象形式的数据
    var Person1 = getPerson1();
    //扩展运算符直接拆分对象传参
    var Person2 = new Person(...Person1);
    
  • 合并对象

    let ab = {...a, ...b}
    
    //如果用户自定义的属性放在扩展运算符后面,扩展运算符内部的同名属性会被覆盖
    let aWithOverrides = {...a, x:1, y:2};
    
    //如果把自定义属性放在扩展运算符前面,就变成了设置新对象的默认值
    let aWithDefaults = {x:1, y:2, ...a};
    

3. 解构赋值中【不一样的】扩展运算符

  • 之前介绍的扩展运算符主要履行的是"拆分"功能,如果仔细观察就会发现,它们都出现在等号的右边或是以实参的形式出现

  • 如果它们出现在等号左边(如解构赋值),那么它们就会执行完全相反的功能——合并剩余项

    //数组
    let [head, ...tail] = [1,2,3,4];	//tail=[2,3,4]
    
    //对象
    let {x,y,...z} = {x:1, y:2, a:3, b:4};	//z = {a:3, b:4}
    
    //形参,这种应用方式又被称为rest参数
    function push(array,...items){
        //items会以数组形式接收所有传入的多余参数
    }
    
  • 记住,在等号左边或形参中出现的...履行收集多余参数的职责;在等号右边或实参中出现的...履行拆分的职责

4. 浅拷贝问题

  • 无论履行哪种职责,扩展运算符始终都是浅拷贝,这意味着:

    • 在解构深层数组/对象的时候,只有第一层会被深拷贝,对于深层扩展运算符解构赋值复制的是这个值的引用而不是副本

      //解构深层对象
      let obj = {a:{b:1}};
      let {...x} = obj;
      obj.a.b = 2;	//尝试修改obj中b的值
      x.a.b;	//结果为2,x中的值也被修改了,说明是浅拷贝
      

      同时也不会复制继承自原型对象的属性

      let o1 = {a:1};
      let o2 = {b:2};
      o2.__proto__ = o1;
      
      let {...o3} = o2;
      o3;		//{b:2}
      o3.a;	//undefined
      
      //值得注意的是,如果直接赋值反而不会有这个问题
      let {o4} = o2;
      o4;		//{b:2}
      o4.a;	//{a:1}
      
    • 在拆分数组/对象的时候,也只有第一层会被深拷贝

      let a:{
          "a1":1,
          "b":{
              "c":2,
              "d":{
                  "d1":3
              }
          }
      }
      let cxy = {...a}
      
      //尝试修改cxy中的值
      cxy.a1 = 1;
      cxy.b.d.d1="cxy"
      
      a.a1;	//1,第一层做了深拷贝
      a..b.d.d1;	//cxy,深层只做了浅拷贝
      
posted @   Solitary-Rhyme  阅读(285)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示