ECMAScript6变量的解构赋值实例详解
数组的解构赋值
ES6允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构(Destructuring)
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//[]
如果解构不成功,变量的值就等于undefined
foo的值都会等于undefined
var[foo]=[]; var[bar,foo]=[1];
不完全解构即等号左边的模式,只匹配一部分的等号右边的数组
let[x,y]=[1,2,3]; x//1 y//2 let[a,[b],d]=[1,[2,3],4]; a//1 b//2 d//4
如果等号的右边不是数组,那么将会报错。
//报错let[foo]=1; let[foo]=false; let[foo]=NaN; let[foo]=undefined; let[foo]=null; let[foo]={};
解构赋值不仅适用于var命令,也适用于let和const命令
var[v1,v2,...,vN]=array; let[v1,v2,...,vN]=array; const[v1,v2,...,vN]=array;
对于Set结构,也可以使用数组的解构赋值。
let[x,y,z]=newSet(["a","b","c"]); x//"a"
只要某种数据结构具有Iterator接口,都可以采用数组形式的解构赋值
function*fibs(){ vara=0; varb=1; while(true){ yielda; [a,b]=[b,a+b]; } } var[first,second,third,fourth,fifth,sixth]=fibs(); sixth//5
fibs是一个Generator函数,原生具有Iterator接口。解构赋值会依次从这个接口获取值
解构赋值允许指定默认值。
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,默认值就不会生效,因为null不严格等于undefined
functionf(){ console.log('aaa'); } let[x=f()]=[1]; //等价于 letx; if([1][0]===undefined){ x=f(); }else{ x=[1][0]; }
如果默认值是一个表达式,那么这个表达式是惰性求值的,即只有在用到的时候,才会求值
默认值可以引用解构赋值的其他变量,但该变量必须已经声明
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]=[];//ReferenceError
是因为x用到默认值y时,y还没有声明
对象的解构赋值
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:foo,bar:bar}={foo:"aaa",bar:"bbb"};
对象的解构赋值的内部机制,是先找到同名属性,然后再赋给对应的变量。真正被赋值的是后者,而不是前者
var{foo:baz}={foo:"aaa",bar:"bbb"}; baz//"aaa" foo//error:fooisnotdefined
上面代码中,真正被赋值的是变量baz,而不是模式foo
变量的声明和赋值是一体的。对于let和const来说,变量不能重新声明,所以一旦赋值的变量以前声明
过,就会报错
letfoo; let{foo}={foo:1}; //SyntaxError:Duplicatedeclaration"foo" letbaz; let{bar:baz}={bar:1}; //SyntaxError:Duplicatedeclaration"baz"
因为var命令允许重新声明,所以这个错误只会在使用let和const命令时出现。如果没有第二个let命令,上面的代码就不会报错
letfoo; ({foo}={foo:1});//成功 letbaz; ({bar:baz}={bar:1});//成功
和数组一样,解构也可以用于嵌套结构的对象
varobj={ p:[ "Hello", {y:"World"} ] }; var{p:[x,{y}]}=obj; x//"Hello" y//"World"
这时p是模式,不是变量,因此不会被赋值
varnode={ loc:{ start:{ line:1, column:5 } } }; var{loc:{start:{line}}}=node; line//1 loc//error:locisundefined start//error:startisundefined
只有line是变量,loc和start都是模式,不会被赋值
嵌套赋值的例子。
letobj={}; letarr=[]; ({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="Somethingwentwrong"}={}; msg//"Somethingwentwrong"
默认值生效的条件是,对象的属性值严格等于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属性,对应一个子对象。该子对象的bar属性,解构时会报错。因为foo这时等于undefined,再取子属性就会报错
要将一个已经声明的变量用于解构赋值,必须非常小心
//错误的写法 varx; {x}={x:1}; //SyntaxError:syntaxerror //正确的写法 ({x}={x:1});
因为JavaScript引擎会将{x}理解成一个代码块,从而发生语法错误。只有不将大括号写在行首,避免JavaScript将其解释为代码块,才能解决这个问题
对象的解构赋值,可以很方便地将现有对象的方法,赋值到某个变量
let{log,sin,cos}=Math;
将Math对象的对数、正弦、余弦三个方法,赋值到对应的变量上,使用起来就会方便很多
字符串的解构赋值
字符串也可以解构赋值。此时字符串被转换成了一个类似数组的对象
const[a,b,c,d,e]='hello'; a//"h" b//"e" c//"l" d//"l" e//"o"
类似数组的对象都有一个length属性,因此还可以对这个属性解构赋值
let{length:len}='hello'; len//5
数值和布尔值的解构赋值
解构赋值时,如果等号右边是数值和布尔值,则会先转为对象
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
函数参数的解构赋值
functionadd([x,y]){ returnx+y; } add([1,2]);//3
函数参数的解构也可以使用默认值
functionmove({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等于默认值
functionmove({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就会触发函数参数的默认值
圆括号问题
解构赋值虽然很方便,但是解析起来并不容易。对于编译器来说,一个式子到底是模式,还是表达式,没有办法从一开始就知道,必须解析到(或解析不到)等号才能知道如果模式中出现圆括号怎么处理。ES6的规则是,只要有可能导致解构的歧义,就不得使用圆括号。但是,这条规则实际上不那么容易辨别,处理起来相当麻烦。因此,建议只要有可能,就不要在模式中放置圆括号
不能使用圆括号的情况
1.变量声明语句中,不能带有圆括号
//全部报错 var[(a)]=[1]; var{x:(c)}={}; var({x:c})={}; var{(x:c)}={}; var{(x):c}={};} var{o:({p:p})}={o:{p:2}};
2.函数参数中不能使用圆括号
//报错 functionf([(z)]){returnz;}
3.赋值语句中,不能将整个模式,或嵌
套模式中的一层,放在圆括号之中
将整个模式放在模式之中,导致报错
//全部报错 ({p:a})={p:42}; ([a])=[5];
将嵌套模式的一层,放在圆括号之中,导致报错
[({p:a}),{x:c}]=[{},{}];
可以使用圆括号的况
赋值语句的非模式部分,可以使用圆括号
[(b)]=[3];//正确 ({p:(d)}={});//正确 [(parseInt.prop)]=[3];//正确
首先它们都是赋值语句,而不是声明语句;其次它们的圆括号都不属于模式的一部分。第一行语句中,模式是取数组的第一个成员,跟圆括号无关;第二行语句中,模式是p,而不是d;第三行语句与第一行语句的性
质一致
用途
1.交换变量的值
[x,y]=[y,x];
2.从函数返回多个值
//返回一个数组 functionexample(){ return[1,2,3]; } var[a,b,c]=example(); //返回一个对象 functionexample(){ return{ foo:1, bar:2 }; } var{foo,bar}=example();
3.函数参数的定义
解构赋值可以方便地将一组参数与变量名对应起来
functionf([x,y,z]){...} f([1,2,3]); //参数是一组无次序的值 functionf({x,y,z}){...} f({z:3,y:2,x:1});
4.提取JSON数据
varjsonData={ id:42, status:"OK", data:[867,5309] }; let{id,status,data:number}=jsonData; console.log(id,status,number); //42,"OK",[867,5309]
5.函数参数的默认值
jQuery.ajax=function(url,{ async=true, beforeSend=function(){}, cache=true, complete=function(){}, crossDomain=false, global=true, //...moreconfig }){ //...dostuff };
6.便利Map结构
varmap=newMap(); map.set('first','hello'); map.set('second','world'); for(let[key,value]ofmap){ console.log(key+"is"+value); } //firstishello //secondisworld //获取键名 for(let[key]ofmap){ //... } //获取键值 for(let[,value]ofmap){ //... }
7.输入模块的指定方法
const{SourceMapConsumer,SourceNode}=require("source-map")
总结
以上所述是小编给大家介绍的使用ECMAScript6变量的解构赋值实例详解,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对毛票票网站的支持!