什么是解构(Destructuring)?
ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构。
let [a, b, c] = [1, 2, 3];
数组解构的特点有哪些?
-
属于“模式匹配”,只要等号两边的模式相同,左边的变量就会被赋予对应的值。
-
解构不成功,变量的值就等于
undefined。 -
左边的模式,只匹配一部分的等号右边的数组,解构依然可以成功。
-
如果等号的右边不是数组(或者严格地说,不是可遍历的结构),那么将会报错。
// 报错 let [foo] = 1; let [foo] = false; let [foo] = NaN; let [foo] = undefined; let [foo] = null; let [foo] = {}; -
Set 结构,也可以使用数组的解构赋值。
let [x, y, z] = new Set(['a', 'b', 'c']); -
具有 Iterator 接口的数据,都可以采用数组形式的解构赋值。
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 -
解构赋值允许指定默认值。
let [x, y = 'b'] = ['a', undefined]; // x='a', y='b' -
默认值判断使用严格相等运算符(
===),仅严格等于undefined生效,‘’与null不生效。 -
默认值可以引用解构赋值的其他变量,但该变量必须已经声明。
-
默认值如果是一个表达式,那么这个表达式是惰性求值的,即只有在用到的时候,才会求值。
对象的解构赋值特点有哪些?
-
变量必须与属性同名,才能取到正确的值。
-
解构失败,变量的值等于
undefined。 -
对象的方法,可以赋值到某个变量。
// 例一 let { log, sin, cos } = Math; // 例二 const { log } = console; log('hello') // hello -
变量名与属性名不一致,必须写成下面这样。
let { foo: baz } = { foo: 'aaa', bar: 'bbb' }; baz // "aaa" -
解构也可以用于嵌套结构的对象。
let obj = { p: [ 'Hello', { y: 'World' } ] }; let { p: [x, { y }] } = obj; x // "Hello" y // "World" // p是模式,不是变量,因此不会被赋值。要赋值的写成:let { p, p: [x, { y }] } = obj; -
解构模式是嵌套的对象,而且子对象所在的父属性不存在,那么将会报错。
// 报错 let {foo: {bar}} = {baz: 'baz'}; -
对象的解构赋值可以取到继承的属性。
-
属性名可以是表达式。
let arr = [1, 2, 3]; let {0 : first, [arr.length - 1] : last} = arr; first // 1 last // 3 -
将一个已经声明的变量用于解构赋值,必须非常小心。
// 错误的写法 let x; {x} = {x: 1}; // SyntaxError: syntax error // 正确的写法 let x; ({x} = {x: 1});
字符串的解构赋值
字符串也可以解构赋值。这是因为此时,字符串被转换成了一个类似数组的对象。
const [a, b, c, d, e] = 'hello';
a // "h"
b // "e"
数值和布尔值的解构赋值
解构赋值的规则是,只要等号右边的值不是对象或数组,就先将其转为对象。由于undefined和null无法转为对象,所以对它们进行解构赋值,都会报错。
但是数值和布尔值可以先转为对象,因此不会报错。
函数参数的解构赋值
- 函数的参数也可以使用解构赋值。
- 函数参数的解构也可以使用默认值。
undefined就会触发函数参数的默认值。
[[1, 2], [3, 4]].map(([a, b]) => a + b);
// [ 3, 7 ]
function move({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]
[1, undefined, 3].map((x = 'yes') => x);
// [ 1, 'yes', 3 ]
解构时不能使用圆括号的情况有哪些?
- 变量声明语句
- 函数参数
- 赋值语句的模式
可以使用圆括号的情况有哪些?
赋值语句的非模式部分,可以使用圆括号。
let b; // 先声明
[(b)] = [3]; // 正确
({ p: (d) } = {}); // 正确