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总结:
- 只能在Generator函数内部使用
- 运行.next(),遇到一个yield命令,就暂停
- .next()的返回值表示一个状态{value,done}
- 再运行.next(),从之前遇到的那个yield [表达式]处恢复运行
- 当.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
上面最后一个表达式之所以会报错,是因为g
用h
做默认值时,h
还没有声明。