ES6 允许按照一定的模式,从数组和对象中提取值,对变量进行赋值,这个被称为解构。
解构的用途
- 交换变量的值
- 从函数返回多个值
- 函数参数的定义
- 提取JSON数据
- 函数参数的默认值
- 遍历Map结构
- 输入模块的指定方法
1、数组解构赋值
(1) 完全解构,这种写法属于 “模式匹配”,只要等号两边的模式相同,左边的变量就会被赋予对应的值。如:
1 | let [foo, [[bar], baz]] = [1, [[2], 3]]; |
(2) 不完全解构,等号左边的模式只匹配到一部分等号右边的数组。这种情况下依然可以解构成功。
1 | let [x, y] = [1, 2, 3]; |
如果等号的右边不是数组的话,就会报错。
1
2
3
4
5
6
7 // 报错
let [foo] = 1;
let [foo] = false;
let [foo] = NaN;
let [foo] = undefined;
let [foo] = null;
let [foo] = {};事实上,只要某种数据结构具有 Iterator 接口,都可以采用数组形式的解构赋值。
1
2
3
4
5
6
7
8
9
10
11 function* fibs() {
let a = 0;
let b = 1;
while (true) {
yield a;
[a, b] = [b, a + b];
}
}
let [first, second, third, fourth, fifth, sixth] = fibs();
sixth // 5上面代码中,fibs是一个 Generator 函数,原生具有 Iterator 接口。解构赋值会依次从这个接口获取值。
2、对象的解构赋值
对象解构赋值和数组的解构赋值不一样。数组的元素是按次序排列的,变量的取值由它的位置决定;而对象的属性没有次序,变量必须与属性同名,才能取到正确的值。
1 |
|
如果变量名与属性名不一致,必须写下面这样。
1 |
|
对象的解构赋值机制是 先找到同名属性,然后再赋值给对应的变量。前者是匹配的模式,后者才是真正的变量。真正被赋值的应该是变量。
1 |
|
如果解构失败,变量的值等于undefined。1
2let {foo} = {bar: 'baz'};
foo // undefined
如果解构模式是嵌套的对象,而且子对象所在的父属性不存在,那么将会报错。等号左边对象的foo属性,对应一个子对象。该子对象的bar属性,解构时会报错。原因很简单,因为foo这时等于undefined,再取子属性就会报错,请看下面的代码。如:
1 | let {foo: {bar}} = {baz: 'baz'}; |
3、字符串的解构赋值
字符串也可以解构赋值。这是因为此时,字符串被转换成了一个类似数组的对象。类似数组的对象都有一个length属性,因此还可以对这个属性解构赋值。
1 |
|
4、函数参数解构赋值
函数参数的解构也可以使用默认值
1 |
|
5、默认值
(1)解构赋值允许指定默认值。因为ES6内部使用严格的相等运算符(===),如果一个数组成员不严格等于undefined,默认值不会生效的。如:
1 |
|
(2)如果默认值是一个表达式的话,那么表达式是惰性求值的,即只有在用到的时候,才会求值。
1 |
|
因为x能取到值,所以函数f根本不会执行。
6、具体用途
(1)交换变量的值
1 |
|
(2)从函数返回多个值
1 |
|
(3)函数参数的定义
1 | // 参数是一组有次序的值 |
(4)提取JSON数据 ,快速提取 JSON 数据的值。解构赋值对提取JSON对象中的数据,尤其有用。
1 | let jsonData = { |
(5)函数参数的默认值。 指定参数的默认值,就避免了在函数体内部再写var foo = config.foo || ‘default foo’;这样的语句。
1 |
|
(6)遍历Map结构, 任何部署了Iterator接口的对象,都可以用for…of循环遍历。Map结构原生支持Iterator接口,配合变量的解构赋值,获取键名和键值就非常方便。
1 | var map = new Map(); |
(7)输入模块的指定方法加载模块时,往往需要指定输入哪些方法。解构赋值使得输入语句非常清晰。
1 | const { SourceMapConsumer, SourceNode } = require("source-map"); |