1. 数组的解构赋值
基本用法
let [a, b, c] = [1, 2, 3];
let [a,,c] = [1,2,3];
let [a,...b] = [1,2,3]; // a=1; b=[2,3]
// set 结构也可以
let [x, y, z] = new Set(['a', 'b', 'c']);
// Iterator 接口的也可以
function* fibs(){
yield 1;
yield 2;
yield 3;
yield 4
}
let [first, second, third] = fibs();
third // 3
默认值
let [a=2] = [1];
若值为全等 undefined, 则才为默认值
let [a=2] = [undefined]; // a=2
let [a=2] = [null]; //a = null
let [a=2] = null; // 报错, 如果模式不是数组, 因为会两边不匹配
let [a=2] = undefined; // 报错
若默认值是一个表达式, 那么这个表达式是 惰性求值, 只有用到的时候才会求值
function f(){
console.log('fffff'); // 这里不会执行
}
let [a=f()] = [1];
a; // 1
// 相当于执行了下面
if( [1][0] === undefined ){
a = f();
}else{
a = 1;
}
2. 对象的解构赋值
let {a=3} = {a: 1};
a; // 1
其实相当于:
let {a: a=3} = {a: 1};
// 有点类似于下面的写法
let _temp = {a: 1};
let a = _temp.a || 3;
解构赋值给空数组和空对象
let [a=3] = {} // ?会报错: Uncaught TypeError: undefined is not a function
let {a=3} = [] // 正确 a = 3;
下面的两种写法是一样的, 数组元素是按次序, 变量的取值由它对应的属性名决定。
let {a, b} = {a: 1, b: 2}
let {b, a} = {a: 1, b: 2}
如果变量名与属性名不一致, 写成下面这样, a 是匹配的模式, c 才是变量
let {a:c} = {a: 1, b: 2}
c; //1
说明对象的解构赋值是下面形式:
let {a, b} = {a: 1, b: 2};
// 等价于下面
let {a:a, b:b} = {a: 1, b: 2}
对象也可以进行嵌套
let {a: [{b}, c]} = {a: [{b: 2}, 3]}
a; // undefined
b; // 2
c; // 3
嵌套赋值例子:
let obj = {};
let arr = [];
( {a: obj.q, b: arr[0]} = {a: 1, b: 2} );
obj; // {q: 1}
b; // [2]
解构也可以指定默认值, 也是必须 === undefined
let { a=3 } = {a: 1};
a; //1
let { a=3 } = {a: null};
a; //null
let {a=4} = {a: undefined};
a; // 4
如果解构失败,变量的值等于undefined
let {a} = {b: 2};
a; // undefined
如果解构模式是嵌套的对象,而且子对象所在的父属性不存在,那么将会报错。
// 报错
let {foo: {bar}} = {baz: 'baz'};
相当于:
let _temp = {baz: 'baz'};
{bar} = _temp.foo;
bar = _temp.foo.bar;
已经声明的变量用于解构赋值, 会将 {x}理解成一个代码块 而不是一个语句, 所以要有括号
let x;
{x} = {x: 1}; // Uncaught SyntaxError: Unexpected token =
let x;
({x} = {x: 1}); // 正确
{foo} = {foo: 1}; // 若不用let 也是正确的, foo 直接挂载到 window 下
3. 字符串的解构赋值
// 字符串转换成 类似数组
const [a,b] = 'hello';
a; // h
b; // e
// 字符串类似对象, 它有一个length 的属性
let {length : len} = 'hello';
4. 数值和布尔值的解构赋值
数值和布尔值都会转好成 包装对象
// 相当于s = 123.toStirng
let {toString: s} = 123;
// 相当于 s = true.toString
let {toString: s} = true;
解构赋值的规则是,只要等号右边的值不是对象或数组,就先将其转为对象。
由于undefined和null无法转为对象,所以对它们进行解构赋值,都会报错。
let {a: 1} = null; // error
let {a: 1} = undefined; // error
5. 函数参数的解构赋值
function add([x, y]){
return x + y;
}
add([1, 2]); // 3
相当于 [x, y] = [1, 2];
对于 map
// [5, 10]
[1, 2].map( (a) => a *5 );
// [3, 7]
[[1,2], [3,4]].map( ([a,b]) => a+ b )
函数参数的解构也可以使用默认值。
// 只有当传递的参数为undefined 或不传参数的时候, 才会执行 {a, b} = {a: 1, b: 3}
function move({a, b} = {a: 1, b: 2}){
return [a,b]
}
move({a: 3, b: 4}); // [3, 4]; 等价 {a, b} = {a: 3, b: 4}
move({a: 3}); // [3, undefined]; 等价 {a, b} = {a: 3}
move({}); // [undefined, undefined]; 等价 {a, b} = {}
move([]); // [undefined, undefined]; 等价 {a, b} = []
move(null); // 报错; 等价 {a, b} = null
move(); // [1, 2]; 等价 {a, b} = {a: 1, b: 2}
move(undefined); // [1, 2]; 等价 {a, b} = {a: 1, b: 2} // 同上面道理
function move({x = 0, y = 0} = {x: 100, y: 200}) {
return [x, y];
} move({x: 3, y: 4}); // [3, 4]
move({x: 3}); // [3, 0]
move({}); // [0, 0]
move(); // [100, 200]
undefined就会触发函数参数的默认值。
[1, undefined, 3].map( (a = 2) => a ); // [1, 2, 3]
6. 圆括号的问题
使用圆括号的情况
赋值语句并且非模式部分,可以使用圆括号。
({ p: (d) } = {p: 3}); // 正确, 这里d是非模式, p是模式, 最后 d = 3
let ({ p: (d) } = {}); // 错误, 因为是声音语句
[(b)] = [3]; // 正确, 说明这个b是非模式部分, 有点类似于 [0:(b)] = [3], 直接这么写会报错
({(a)} = {a: 3}); // 错误, 说明是这么执行 {(a): a} = {a: 3}; 括号加在了 a的模式部分
7.用途
1) 交换变量的值
let x=1;
let y=2;
[x,y] = [y,x];
2) 从函数返回多个值
function f(){
return {
a: 1,
b: 2
}
}
let {a, b} = f();
function f(){
return [2, 3]
}
let [a, b] = f();
3) 函数参数的定义
function f([x, y, z]){
console.log(arguments[0]); // [1,2,3]
console.log(x, y, z);
}
f([1,2,3]);
function f({x, y, z}){
console.log(arguments[0]); // arguments[0] 其实就是 {x: 1, y:2, z: 3}
console.log(x, y, z); // x = 1, y = 2, z = 3;
}
f({x: 1, y: 2, z: 3});
4) 提取JSON数据
let o = {
a: 1,
b: 2
}
let {a, b} = o;
5) 函数参数的默认值
function f({x = 2, y = 3}){
console.log(x, y);
}
f({});
f(); // error, 必须至少传入空对象, 否则会报错
6)遍历Map结构
var map = new Map();
map.set('first', 'hello');
map.set('second', 'world');
for(let item of map){
console.log(item); // item 分别输出 ["first", "hello"], ["second", "world"]
}
所以可以写成:
for(let [key, value] of map){
cnosole.log(key, value);
}
// 获取key 的值
for( let [key] of map){
console.log(key);
}
// 获取value 的值
for( let [, value] of map){
console.log(value);
}
7)输入模块的指定方法
const {a, b} = require('./test2')
import {a, b} from './test2';