• 变量的解构赋值 ES6


    1.先来说说数组的解构赋值。

    【基本用法】

    ES6允许按照一定模式,从数组和对象中提取值,然后对变量进行赋值,这种被称为解构。

    
      var a = 1;
    
      var b = 2;
      var c = 3;
    
    //ES6:
    
    var  [a,b,c] = [1,2,3];//本质上,这种称为模式匹配,只要等号两边的模式相同,左边变量就会被赋予右边对应的值
    
    

    下面是嵌套数组进行解构的例子

    
    let [foo,[[bar],baz]] = [1,[[2],3]];
    
    foo //1
    
    bar //2
    
    baz //3
    
    let [ , , third] = ["foo","bar","baz"];
    
    third //"baz"
    
    let [x, , y] = [1,2,3];
    
    x // 1;
    
    y // 3;
    
    let [head,...tail] = [1,2,3,4];
    
    head // 1
    
    tail //[2,3,4]
    
    let [x,y,...z] = ['a'];
    
    x // "a"
    
    y // undefined
    
    z // []
    
    

    (1)如果解构不成功,变量的值就等于undefined

    
      var [foo] = [];
    
      var [bar,foo] = [1];
    
      //以上两种情况都属于解构不成功,foo的值都会等于undefined
    
    

    (2)另一种情况,就是不完全解构,即等号左边的模式只匹配等号右边数组的一部分,这种情况下,解构依然可以成功。

    let [x,y] = [1,2,3];

    x // 1

    y // 2

    let [a,[b],d] = [1,[2,3],4];

    a // 1

    b // 2

    d // 4

    上面的两个例子都属于不完全解构,但是可以成功

    (3)如果等号右边不是数组,不是可以遍历的解构,那么就会报错。

    解构赋值不仅适用于var命令,也适用于let和const命令

    
      var [v1,v2,...,vN] = array;
    
      let  [v1,v2,...,vN] = array;
    
      const [v1,v2,...,vN] = array;
    
    

    对于Set结构,也可以使用数组的解构赋值

    
    let [x,y,z] = new Set(["a","b","c"])
    
    x // "a"
    
    

    事实上,只要某种数据结构具有Iterator接口,都可以采用数组形式的解构赋值。

    
      function* fibs(){
    
        var a = 0;
    
        var b = 1;
    
        while(true){
    
          yield a;
    
          [a,b] = [b,a+b];
    
        }
    
      }
    
      var [first,second,third,fourth,fifth,sixth] = fibs();
    
      console.log(first); // 0
    
      console.log(second); // 1
    
      console.log(third); // 1
    
      console.log(fourth); // 2
    
      console.log(fifth); // 3
    
      console.log(sixth); // 5
    
    

    在看书上这部分的时候,不是太懂,然后通过打印每个值,发现了一丢丢原理。不过这只是我的一点理解,也不知道对不对。

    上面这个fibs这个函数,里面一直在对[a,b]这个数组赋值,在进入while循环的时候,[a,b]就已经有一个值了:[0,1].然后随着while循环的继续执行,

    [a,b]这个数组就一直被赋值:

    [a,b] = [0,1]

    [a,b] = [1,1];

    [a,b] = [1,2];

    [a,b] = [2,3];

    [a,b] = [3,5];

    [a,b] = [5,8];

    然后var [first,second,third,fourth,fifith,sixth] = fibs();

    解构赋值会依次从这个接口获取值。yield a,这里简单粗暴的理解为返回a的值,所以打印出来的first到sixth是0 1 1 2 3 5.

    【默认值】

    解构赋值允许指定默认值

    
      var [foo = true] = [];
    
      foo // true
    
      [x,y = 'b'] = ['a'] //x= 'a',y = 'b'
    
      [x,y = 'b'] = ['a',undefined] // x = 'a',y= 'b'
    
    

    注意:ES6内部使用严格相等运算符(===)判断一个位置是否有值,所以,如果一个数组成员不严格等于undefined,默认值是不会生效的

    
      var [x=1] = [undefined];
    
          // x = 1
    
      var [x =1] = [null];
    
      x//null  如果一个数组成员时null,默认值就不会生效,
    
    

    如果默认值是一个表达式,那么这个表达式是惰性求值的,即只有在用到的时候才会求值。

    
      function f(){
    
        console.log('aaa');
    
      }
    
      let [x = f()] = [1];//这时候x能取到值,所以f函数根本不会执行。
    
    

    默认值可以引用解构赋值的其他变量,但该变量必须已经声明

    
      let  [x = 1,y = x] = [];//x = 1,y = 1
    
      let [x =1,y = x] = [2];//x = 2,y = 2
    
      let [x = 1,y = x] = [1,2];//x = 1,y = 2
    
      let [x = y,y = 1] = [];//报错
    
      因为x用到默认值y时,y还没有被声明
    
    

    2.接着说说对象的解构赋值

    解构不仅可以用于数组,还可以用于对象

    
    var {foo,bar} = {foo:"aaa",bar:"bbb"};
    
    foo// "aaa"
    
    bar//"bbb"
    
    

    注意:对象的解构与数组有一个重要的不同。数组的元素是按次序排列的,变量的取值由它的位置决定;而对象的属性没有次序,变量必须与属性同名,才能找到正确的值。

    
    var {bar,foo} = {foo:"aaa",bar:"bbb"};
    
    foo//"aaa"
    
    bar//"bbb"
    
    var {baz} = {foo:"aaa",bar:"bbb"};
    
    baz//undefined
    
    

    如果变量名与属性名不一致,可以写成下面这样:

    
      var {foo:baz} = {foo:"aaa",bar:"bbb"};
    
      baz // "aaa"
    
      let obj = {first:"aaa",last:"bbb"};
    
      let{first:f,last:l} = obj
    
      f  //"aaa"
    
      l //"bbb"
    
      这个实际上说明,对象的解构赋值是以下形式的简写:
    
      var  {foo:foo,bar:bar} = {foo:"aaa",bar:"bbb"};
    
    

    也就是说,对象的解构赋值的内部机制,是先找到同名属性,然后再赋给对应的变量。真正被赋值的是后者,不是前者。

    采用这种写法时,变量的声明和赋值是一体的,对于let和const而言,变量不能重新声明,所以一旦赋值的变量以前声明过,就会报错。

    let foo;
    
    let {foo} = {foo:1};//报错,已经声明过了
    
    let baz;
    
    let {bar:baz} = {bar:1};//baz已经声明过了
    
    

    注意:不过这个错误只会在使用let和const命令时出现,因为var允许重新声明

      let foo;
    
      ({foo}={foo:1});//成功
    
    

    和数组一样,解构也可以用于嵌套解构的对象

    
      var obj = {p:["hello",{y:"world"}]};
    
      var {p:[x,{y}]} = obj;
    
      x//"hello"
    
      y//"world"
    

    注意这时候p是模式,不是变量,所以不会被赋值

      var node = {

        loc:{

          start:{

            line:1,column:5

          }

        }

      }

      var {loc:{start:{line:1,column:5}}} = node;

      line //1

      loc //loc is undefined

      start // start is undefined

    
      上面代码中,只有line是变量,loc和start都是模式,不会被赋值
    
      下面是嵌套赋值的例子
    

      ({foo:obj.prop,bar:arr[0]} = {foo:123,bar:true});

      obj//{prop:123}

      arr //[true]

    
      对象的解构赋值也可以指定默认值
    

      var {x = 3} ={};

      x //3

      var {x,y = 5} = {x:1};

      x // 1

      y // 5

      var {message :msg = "something went wrong"} = {};

      msg // something went wrong

    
      默认值生效的条件是,对象的属性值严格等于undefined
    

      var {x = 3} = {x :undefined};

      x // 3

      var {x=3} = {x:null};

      x // null

    
      如果解构失败,变量的值等于undefined
    

      var {foo} ={bar:'baz'};

      foo // undefined

    
      如果解构模式是嵌套的对象,而且子对象所在的父属性不存在,会报错。
    

      var {foo:{bar}} = {baz:'baz'};

    
      foo这是等于undefined,再取子属性就会报错
    
      
    
      //错误的写法:
    
      var x;
    
      {x} = {x:1};//这时候javascript引擎会把{x}理解成一个代码块,从而发生错误。
    
      //正确的写法
    
      ({x} = {x:1});
    
      还有解构赋值,允许等号左边的模式中不放置任何变量名:
    

      ({} = [true,false]);

      ({} = 'abc');

      ({} = [])

    
      //这些表达式虽然没有意义,但是语法是合法的,可以执行
    
      对象的解构赋值可以很方便的将现有对象的方法赋值到某个变量
    
      let {log,sin,cos} = Math;
    
      //上面将Math对象的取对数,正弦,余弦三个方法赋值到了对应的变量上,这样使用起来会方便很多
    
    3.字符串的解构赋值
    
    字符串也可以解构赋值。这是因为字符串被转换成了一个类似数组的对象。
    
    

      const [a,b,c,d,e] = 'hello';

      a // 'h' b// 'e' ...

      //类似数组的对象都有length属性,因此还可以对这个属性解构赋值。

      let {length:len} = 'hello'

      len // 5

    
    4.数值和布尔值的解构赋值
    
    在解构赋值时,如果等号右边是数值或者布尔值,则先转换为对象
    

    let {toString:s} = 123;

    s === Number.prototype.toString // true

    let {toString:s} = true;

    s === Boolean.prototype.toString // true

    
    上面的代码中,数值和布尔值的包装对象都有toString属性,因此变量s都能取得值
    
    解构赋值的规则是:只要等号右边的值不是对象,就先将其转为对象,由于undefined和null无法转化为对象,所以对他们进行解构赋值都会报错。
    

    let {prop:x} = undefined;//TypeError

    let {prop:y} = null;//TypeError

    
    5.函数参数的解构赋值
    
    

      function add([x,y]){

        return x+y;

      }

      add([1,2]) // 3 注意add的参数不是一个数组,而是通过解构得到的变量x,y

    
    其次,函数参数的解构赋值,也可以是默认值,得看是赋值给等号左边,还是等号右边,等号左边是变量,等号右边是参数。
    
    给定一个例子来理解
    
    (1)默认值在等号左边
    
    

      function move({x=0,y=0} = {}){

        return [x,y];

      }

      move({x:3,y:8}); // [3,8]

      move({x:3}); // [3,0]

      move({});//[0,0]

      move();//[0,0]

    
      上面的代码中,函数move的参数是一个对象,通过对这个对象进行解构,得到变量x和y的值。
    
      如果解构失败,则x和y等于默认值
    
    
    (2)默认值在等号右边
    
    

      function move({x,y} = {x:0,y:0}){

        return [x,y];

      }

      move({x:3,y:8});// [3,8]

      move({x:3});// [3,undefined]

      move({}) // [undefined,undefined]

      move() // [0,0]

    
    上面代码是为函数move的参数指定默认值,而不是为变量x和y指定默认值,所以会得到与前一种不同的结果。
    
    这就是默认值在等号左边和等号右边的区别。一个是真正为变量赋值(左边),一个是为函数参数赋值(右边)。
    
     
    
    还有一点:undefined可以触发函数参数的默认值
    

    [1,undefined,3].map((x = 'yes') =>x)

    
    6.圆括号问题
    
    ES6的规则是,只要可能导致解构歧义,就不得使用圆括号。
    
    因此,建议只要有可能,就不要在模式中放置圆括号
    
    (1)不能使用圆括号的情况
    
    1.变量声明语句中,模式不能带有圆括号
    

    var [(a)] = [1];

    var {x:(c)} = {};

    var {o:({p:p})} = {o:{p:2}};

    
    上面三条语句都会报错,因为它们都是变量声明语句,模式不能使用圆括号。
    
    2.函数参数中,模式不能带有圆括号
    
    函数参数也属于变量声明,因此不能带有圆括号
    

    //报错

    function f([(z)]) {return z;}

    
    3.不能将整个模式或嵌套模式中的一层放在圆括号中、
    

    //报错

    ({p:a}) = {p:42};

    ([a]) = [5];

    
    (2)可以使用圆括号的情况
    
    只有一种:赋值语句的非模式部分可以使用圆括号
    

    [(b)] =[3]; // 正确

    ({p:(d)} = {});//正确

    [(parseInt.prop)] = [3];//正确

    
    上面三条都是正确的,首先他们都是赋值语句,而不是声明语句,其次,它们的圆括号都不属于模式的一部分。
    
     
    
    7.用途
    
    (1)变换变量的值
    
    [x,y] = [y,x];
    
    上面代码交换了变量x和y的值
    
    (2)从函数返回多个值
    
    函数只能返回一个值,如果要返回多个值,只能将其放在数组或对象中返回。有了解构赋值,取出这些值就非常方便
    
    //返回一个数组
    
    

      function example(){

        return [1,2,3];

      }

      var [a,b,c] =example();

    //返回一个对象

    function example(){

      return {

        foo:1,

        baz:2

      };

    }

    var {foo,bar} = example();

    
    (3)函数参数的定义
    
    解构赋值可以方便的将一组参数与变量名对应起来
    
    参数是一组有次序的值(数组)
    
    

      function f([x,y,z]){

        ...

      }

      f([1,2,3]);

    //参数是一组无次序的值(对象)

      function f([x,y,z]){...}

      f({z:3,y:2,x:1});

    
    (4)提取JSON数据
    
    解构赋值对提取JSON对象中的数据尤其有用
    

    var jsonData = {

      id:42,

      status:"ok",

      data:[867,5309]

    }

    let {id,status,data:number} = jsonData;

    console.log(id,status,number);

    //42,ok,[867,5309]

    上面的代码可以快速提取JSON数据的值
    
    (5)函数参数的默认值
    
    

      jquery.ajax = function(url,{
        async = true,

        beforeSend = function(){},

        cache = true,

        // .. more config

      }){

        //... do stuff

      };

    //指定参数的默认值,就避免了在函数体内部再写var foo = config.foo

    
    (6)遍历Map结构
    
    任何部署了Iterator接口的对象,都可以用for ... of循环遍历。Map结构原生支持Iterator接口,配合变量的解构赋值,获取键名和键值就非常方便
    
    

      var map = new Map();

      map.set('first','hello');

      map.set('second','world');

      for(let [key,value] of map){

        console.log(key + "is" + value);

      }

      //first is hello

      //second is world

    
    如果只想获得键名,或者只想获取键值,可以写成下面这样
    
    

      //获取键名

      for(let [key] of map){

        //...

      }

      //获取键值

      for(let [,value] of map){

        //...

      }

    
    (7)输入模块的指定方法
    
      加载模块时,往往需要指定输入哪些方法。解构赋值使得输入语句非常清晰
        
    

      const {SourceMapConsumer,SourceNode} = require("source-map");

  • 相关阅读:
    C# 导入Excel遇到数字字母混合列数据丢失解决
    C# 导出 Excel
    DataGridView 改变行列颜色
    EditPlus使用技巧
    jquery的事件与应用
    jquery操作DOM元素的复习
    jquery笔记
    jquery 和ajax
    jQuery笔记
    CSS相关知识三
  • 原文地址:https://www.cnblogs.com/sminocence/p/6729383.html
Copyright © 2020-2023  润新知