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变量的解构赋值实例详解,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对毛票票网站的支持!