A:什么是解构赋值?
Q:ES6允许按照一定模式从数组和对象中提取值,然后对变量进行赋值,这就是解构。
模式匹配:
let [a, b, c] = [1, 2, 3];
// 相当于
let a = 1;
let b = 2;
let c = 3;
只要等号两边的模式相同,左边的变量就会被赋值给对应的值。
1. 数组的解构赋值
1.1 基本用法
- 变量取值由它的位置决定
let [x, [[y], z]] = [1, [[2], 3]];
x // 1
y // 2
z // 3
let [x, , y] = [1, 2, 3];
x // 1
y // 3
// ... 剩余操作符,把剩余的内容赋值给y
let [x, ...y] = [1, 2, 3];
x // 1
y // [2, 3]
- 解构不成功的时候会返回undefined
let [x, y, ...z] = ['a'];
x // 'a'
y // undefined
z // []
- 不完全解构,但可以解构成功
let [x, y] = [1, 2, 3];
x // 1
y // 2
- 等号右边不是数组会报错
// error
let [x] = 1;
let [x] = true;
let [x] = NaN;
let [x] = undefined;
let [x] = null;
let [x] = {};
- 对于Set解构,可以使用解构赋值
let [x, y, z] = new Set(['a', 'b', 'c']);
x // 'a'
如果某种数据结构具有Iterator接口,就可以采用数组形式进行解构赋值。
1.2 默认值
解构赋值允许指定默认值。
let [x = true] = [];
x // true
- ES6内部使用严格相等运算符(===)判断一个位置是否有值。
- 如果一个数组成员不严格等于undefined,则默认值不生效。
let [x, y = 'b'] = ['a'];
x // 'a'
y // 'b'
let [x, y = 'b'] = ['a', 'undefined'];
x // 'a'
y // 'b'
(相等运算符:https://blog.csdn.net/qq_46025031/article/details/114938271)
let [x = 1] = [undefined];
x // 1
// 数组中的undefined严格等于undefined,默认值生效
let [x = 1] = [null];
x // null
// 数组中的null不严格等于undefined,默认值不生效
- 惰性求值:如果默认值为表达式,则表达式是惰性求值的,用到的时候才会求值。
function f() {
console.log(222);
}
let [x = f()] = [1];
x // 1
因为x能取到值,所以f()不会执行。
- 默认值可以引用其他解构赋值的变量
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] = [] // error,x用到默认值y时y还没有声明
2. 对象的解构赋值
- 变量必须与属性同名才能取到正确的值
let {a, b, c} = {a: 'aaa', b: 'bbb'};
a // aaa
b // bbb
c // undefined
- 变量名与属性名不一致
let {a: c} = {a: 'aaa', b: 'bbb'};
c // aaa
- 对象的解构赋值的内部机制是先找到同名属性,然后再赋值给对应的变量。真正被赋值的是后者,而非前者。
let {a: c} = {a: 'aaa', b: 'bbb'};
c // aaa
a // error
// a 是匹配的模式,c 才是变量
- 嵌套结构
let obj = {
p: [
'hello',
{y: 'world'}
]
}
let {p: [x, {y}]} = obj;
// p为模式
x // 'hello'
y // 'world'
// 如果想给p赋值
let {p, p: [x, {y}]} = obj;
p // ['hello', {y: 'world'}]
- 指定默认值
let {x = 3} = {x: undefined};
x // 3
let {x = 3} = {x: null};
x // null
- 解构失败
let {a} = {b: 'bbb'};
a // undefined
3. 字符串的解构赋值
let [a, b, c, d, e] = 'hello';
a // 'h'
b // 'e'
...
- length属性
let {length: len} = 'hello';
len // 5
4. 数值和布尔值的解构赋值
- 如果等号右边是数值和布尔值,会先转为对象
let {toString: s} = 123;
s === Number.prototype.toString // true
let {toString: s} = true;
s === Boolean.prototype.toString // true
- undefined 和 null 无法转为对象,解构时会报错
let {prop: x} = undefined; // error
let {prop: y} = null; // error
5. 函数参数的解构赋值
function f({x = 0, y = 0} = {}) {
return [x, y];
}
f({x: 3, y: 8}); // [3, 8]
f({x: 3}); // [3, 0]
f({}); // [0, 0]
f(); // [0, 0]
6. 圆括号问题
6.1 不能使用圆括号的情况
- 变量声明语句
let [(a)] = [1]; // error
let {x: (c)} = {}; // error
- 函数参数
function f([(z)]) {
return z;
} // error
- 赋值语句的模式
// 整个模式放在圆括号中,报错
({p: a}) = {p: 12};
([a]) = [5];
// 部分模式放在圆括号中,报错
[({p: a}), {x: c}] = [{}, {}];
6.2 可以使用圆括号的情况
赋值语句的非模式部分可以使用圆括号。
[(b)] = [3];
({p: (d)} = {});
[(parseInt.prop)] = [3];
7. 用途
- 交换变量的值
- 从函数返回多个值
- 函数参数的定义
- 提取JSON数据
- 函数参数的默认值
- 遍历Map结构
- 输入模块的指定方法