let的解构赋值_Destructuring assignment(解构赋值)in ES6

ES6允许按照一定模式,从数组和对象(以及字符串、数值、布尔值、函数参数等)中提取值,按照对应位置给变量进行赋值,这被称为解构赋值。首先,假定你已经了解了什么是解构赋值,我们先来快速看一下它的常见用途。

交换变量的值

let x=1,y=2;

[x,y]=[y,x];

与传统的引入中间变量进行值交换的方式相比,这种写法不仅简洁,而且易读,语义非常清晰

解析函数多返回值

JS中函数只能返回一个值,如果要返回多个值,只能将它们放在数组或对象里返回,通过解构赋值,我们可以很方便的将这些值取出来并赋给其它变量。

//返回一个数组

function arr(){

return [1,2,3];

}

let [x,y,z]=arr();

//返回一个对象

function obj(){

return {

foo:1,

bar:2

}

}

let {foo,bar}=obj();

定义函数多参数传入方式

解构赋值可以很方便地将一组实参与形参变量名对应起来。

//参数是一组有序的值

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

f([1,2,3]);

//参数是一组无序的值

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

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

4.提取JSON数据

解构赋值对提取JSON对象中数据,尤其有用。

let jsonData={

id:20,

status:'OK',

data:[12,34]

};

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

console.log(id,status,number);//20 'OK' [12,34]

5.遍历部署了Iterator接口的数据结构时,即在for ... of循环遍历自身每一项时,可以直接多参数传值。Map结构原生支持Iterator接口,使用变量的解构赋值,可以很方便的获取键名和键值。

var map=new Map();

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

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

for(let item of map){

console.log(item);

}

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

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

}

for(let [i,j] of map){

console.log(i+' is '+j);//结果同上

}

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

//获取键名

for (let [key] of map){...}

//获取键值

for (let [,value] of map){...}

6.获取模块的指定方法

加载模块后,往往需要再次指定变量获取模块的某些方法。解构赋值直接精简了这一过程。

const {SourceMap,SourceNode} = require('source-map');

接下来详细介绍Destructuring assignment.

1. 数组的解构赋值

以前,为变量赋值,只能直接指定值

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

现在ES6允许这样

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

看起来和golang的多参数赋值差不多,这里的代码实际上表示从数组中提取值,按照对应位置赋给变量。本质上,这种写法属于“模式匹配”,只要等号两边的模式相同,左边的变量就会被赋予对应的值。

let [foo,[[bar],bar]]=[1,[[2],3]];

let [,,third]=['foo','bar','baz']

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

let [head,...tail]=[1,2,3,4];

let [x,y,...z]=['a'];

如果解构不成功,变量的值将等于undefined。若等号右边的值不是可遍历的数据结构(没有Iterator接口),那么将会报错

//报错

let [foo]=1;

let [foo]=undefined;

let [foo]=null;

let [foo]=false;

let [foo]=NaN;

let [foo]={};//注意,普通对象本身不具备Iterator接口,不可遍历

//for循环遍历,数组和对象可使用for...in遍历,其中数组遍历时传入的参数值是索引,对象传入的是属性,数组还可以使用forEach方法进行遍历

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

let [x,y,z]=new Set(['a','b','c']);

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

function* fibs(){

let a=0,b=1;

while(true){

yield a;

[a,b]=[b,a+b];

}

}

let [first,second,third,fourth,fifth,sixth]=fibs();

console.log(sixth);//5

上面代码中,fibs是一个Generator函数,原生具有Iterator接口,解构赋值会依次从这个接口获取值。

解构赋值允许指定默认值,只有当数组成员严格等于undefined时,默认值才会生效。如果默认值是一个表达式,那么这个表达式是惰性求值的,即只有在用到的时候,才会求值。

function f(){...}

let [x=f()]=[1];

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

2. 对象的解构赋值

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

let {foo,bar}={foo:'aaa',bar:'bbb'}

比较常见的是在Node导出模块对象时:

let a=1,b=2;

//let obj={a,b}

module.exports={a,b}

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

let {foo,bar}={bar:'bbb',foo:'aaa'}

let {baz}={foo:'aaa',bar:'bbb'}

上面的第一行语句,等号左边的两个变量的次序与等号右边两个同名属性的次序不一致,但是对取值完全没有影响,第二行语句中左边的变量在等号右边没有对应的同名属性名,所以取不到值,为undefined

若所需要的变量名明确与属性名不一致,则必须写成下面这样:

let {foo:baz}={foo:'aaa'};

console.log(baz);//aaa

let {first:f,last:l}={first:'hello',last:'world'}

console.log(f,l);//hello world

这实际上说明,对象的解构赋值是下面形式的简写:

let {foo:foo,bar:bar}={foo:'aaa',bar:'bbb'}

也就是说,对象的解构赋值的内部机制,是先找到同名属性,然后再将该属性的值赋给模式匹配的变量,真正被赋值的是后者,而不是前者。对象的解构赋值,可以很方便地将现有对象的方法,赋值到某个变量。

由于数组本质是一种特殊的对象,因此可以对数组进行对象属性的解构

let arr=[1,2,3];

let {0:first,[arr.length-1]:last}=arr;//方括号这种写法,属于“属性名表达式”

console.log(first,last);//1 3

3. 字符串的解构赋值

字符串也可以解构赋值,这是因为字符串此时会先被默认转化为一个类似数组的对象

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

console.log(a,b,c,d,e);

let {length:len}='hello';

console.log(len);// 5 类似数组的对象都有一个length属性

4. 数值和布尔值的解构赋值

解构赋值时,如果等号右边是数值和布尔值,则会先转化为对象。

let {toString:s}=123;

console.log(s);//Number.prototype.toString

let {toString:s}=true;

console.log(s);//Boolean.prototype.toString

解构赋值的规则是,如果等号右边的规则不是对象或者数组时,就先将其转化为对象。若无法转化为对象,如null、undefined,则会报错

5. 函数参数的解构赋值

函数的参数也可以使用解构赋值

function add([x,y]){...}

add([1,2]);

上面代码中,函数add的参数表面上是一个数组,但在传入参数的那一刻,数组参数就被解构成变量x和y,对于函数内部的代码来说,它们能感受到的参数就是x和y.

下面是另一个例子:

[[1,2],[3,4]].map(([x,y])=>x+y);//[3,7]

函数参数的解构赋值也可以使用默认值

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

return [x,y]

}

move();//[0,0]

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

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

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

//只有当传入参数值为`undefined`时,才会考虑默认值,在阅读的时候可以先抛开默认值不看便于阅读

上面代码中,函数move的参数是一个对象,同时设置默认值为{},通过对传入的对象进行解构,得到变量x和y的值,如果解构失败,x、y等于默认值。

注意,下面的写法略微有点不同

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

return [x,y]

}

move();//[0,0]

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

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

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

这里函数参数的默认值为{x:0,y:0},与上面不同。

6. 圆括号问题

在变量声明语句,函数参数以及赋值语句的模式之中,都不能使用等号,只有一种情况下可以使用圆括号:赋值语句的非模式部分。

有疑问加站长微信联系(非本文作者)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值