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

基本用法:

1、

let [a,b,c]=[1,2,3];

a=1,b=2,c=3

2、

let [a,[b,[c]]]=[1,[2,[3]]];//a=1,b=2,c=3
let [,,d]=[3,4,5];//d=5
let [e,,f]=[6,7,8,9];//e=6,f=8
let [g,h,...i]=[10,11,12,13];//g=10,h=11,i=[12,13],...i之后不能再有变量,否则报错
let [j,k,...l]=[14];//j=14,k='undefined',l=[]

如果解构不成功,变量的值就等于undefined,上面的k就是解构不成功,let [k]=[]也会解构不成功;而let [...k]=[]则会成功,因为k是个数组,此时k=[]

还有一种情况是不完全解构,即等号左边的模式只匹配一部分等号右边的数组,这种情况下,解构依然可以成功,例如 let [a,b]=[1,2,3];//a=1,b=2

3、

如果等号的右边不是数组(或者严格地说,不是可遍历的结构),那么将会报错。例如let [a]=1;let [b]=false;let [c]={};let [d]=undefined;这些都会报错,因为都不具备Iterator 接口

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

let [a, b, c] = new Set([1, 2, 3]);//a=1,b=2,c=3

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

  function* fibs() {
      let x = 0;
      let y = 1;
      while (true) {
        yield x;
        [x, y] = [y, x + y];
      }
    }
    let [a, b, c, d, e, f, g] = fibs();//a=0,b=1,c=1,d=2,e=3,f=5,g=8

这里遇到了yield,顺便学一下

yield这个关键字是用来暂停和恢复一个遍历器函数(的运行)的,每次暂停会返回yield后面的值,比如上面的yield x;每次运行到这里都会暂停,然后返回x的值。
a、把上面的yield x改一下
 function* fibs() {
      let x = 0;
      let y = 1;
      while (true) {
        yield [x, y];
        [x, y] = [y, x + y];
      }
    }
    let [a, b, c, d, e, f, g] = fibs();
    console.log("a=", a);
    console.log("b=", b);
    console.log("c=", c);
    console.log("d=", d);
    console.log("e=", e);
    console.log("f=", f);
    console.log("g=", g);

结果如下图:

 b、

function* fibs() {
      let x = 0;
      let y = 1;
      while (true) {
        yield x;
        [x, y] = [y, x + y];
        return;
      }
    }
    let func = fibs();
    console.log("func=", func);
    let a = func.next();
    console.log("a=", a);
    let b = func.next();
    console.log("b=", b);

结果如下图:

第一次调用let a=func.next()是运行到yield x,返回x的值,暂停遍历,不会执行return,所以a的值是{value: 0, done: false},返回的值为x,x=0,value:0,遍历没结束,done:false;

第二次调用let b = func.next()是运行到return,遍历结束,return没有返回值,所以是undefined,遍历结束,所以done:true,b= {value: undefined, done: true}

c、

 function* fibs() {
      let x = 0;
      let y = 1;
      while (true) {
        yield [x, y];
        [x, y] = [y, x + y];
        return y;
      }
    }
    let func = fibs();
    console.log("func=", func);
    let a = func.next();
    console.log("a=", a);
    let b = func.next();
    console.log("b=", b);

d、

  function* fibs() {
      let x = 0;
      let y = 1;
      while (true) {
        let z = yield x;
        console.log("z=", z);
        y = z + y;
        return y;
      }
    }
    let func = fibs();
    console.log("func=", func);
    let a = func.next();
    console.log("a=", a);
    let b = func.next();
    console.log("b=", b);

上面代码let a = func.next();会在yield x暂停,然后let b = func.next();并没有传参数进去,所以z= undefined
  function* fibs() {
      let x = 0;
      let y = 1;
      while (true) {
        let z = yield x;
        console.log("z=", z);
        y = z + y;
        return y;
      }
    }
    let func = fibs();
    console.log("func=", func);
    let a = func.next();
    console.log("a=", a);
    let b = func.next(2);//传2进去
    console.log("b=", b);

传参数进去时,会把参数yield暂停的那一块替换成传进去的参数,此时let z=2;但是第一次调用let a = func.next();是不能在next()里面传参数的

    yield总结:
  1. 只能在Generator函数内部使用
  2. 运行.next(),遇到一个yield命令,就暂停
  3. .next()的返回值表示一个状态{value,done}
  4. 再运行.next(),从之前遇到的那个yield [表达式]处恢复运行
  5. 当.next()传参的时候,yield [表达式]整个被替换为传入的参数

 4、默认值

解构赋值允许指定默认值

let [a=1]=[];//a=1
let [b,c=2]=[1];//b=1,c=2
let [e,f=3]=[4,undefined];//e=4,f=3

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

let [a=1]=[undefined];//a=1
let [b=1]=[null];//b=null

上面代码中,如果一个数组成员是null,默认值就不会生效,因为null不严格等于undefined

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

function func(){
    console.log("111"); 
}

let [a=func()]=[1];

上面代码中,因为a能取到值,所以函数func根本不会执行。

 

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

let [a=1,b=a]=[];//a=1,b=1
let [c=1,d=c]=[2];//c=2,d=2
let [e=1,f=e]=[2,3];//e=2,f=3
let [g=h,h=1]=[];//ReferenceError: h is not defined

上面最后一个表达式之所以会报错,是因为gh做默认值时,h还没有声明。