本文主要内容:
① 字符串的解构赋值
② 数值和布尔值的解构赋值
③ 函数参数的解构赋值
④ 解构赋值过程中圆括号的使用
⑤解构赋值的用途
解构赋值的规则是,只要等号右边的值不是对象或者数组,就先将其转为对象。undefined和null无法转为对象,所以对它们进行解构赋值均会报错
1 字符串的解构赋值
通过解构赋值,字符串被转换为一个类似数组的对象
const [a, b, c, d, e] = 'hello';
a // "h"
b // "e"
c // "l"
d // "l"
e // "o"
此外,类似数组的对象都有一个length的属性,因此还可以对这个属性解构赋值
let {length : len} = 'hello';
len // 5
2 数值与布尔值的解构赋值
解构赋值时,如果等号右边是数值和布尔值,则会先转为对象
// 代码中,数值和布尔值的包装对象都有toString属性,因此变量s都能取到值
let {toString: s} = 123;
s === Number.prototype.toString // true
let {toString: s} = true;
s === Boolean.prototype.toString // true
// 对undefined和null进行解构赋值将会报错
let { prop: x } = undefined; // TypeError
let { prop: y } = null; // TypeError
3 函数参数的解构赋值
// 虽然给add函数传递的是[]数组形式的参数,此时将会进行解构赋值。
// 即 x = 1 ;y = 2
function add([x, y]){
return x + y;
}
add([1, 2]); // 3
[[1, 2], [3, 4]].map(([a, b]) => a + b);
// [ 3, 7 ]
函数参数解构赋值设置默认值
①设置默认值
// 参数形式:{x=0,y=0}={},此时相当于x,y均设置默认值为0。
// {}中没有设置x,y的值,所以均为undefined,所以默认值将生效,即x,y均为0
function move({x = 0, y = 0} = {}) {
return [x, y];
}
// 所以没有传递的参数,将会延用默认值
move({x: 3, y: 8}); // [3, 8]
move({x: 3}); // [3, 0]
move({}); // [0, 0]
move(); // [0, 0]
②通过解构赋值 给{x,y}整体赋值
// 参数形式:{x,y} = {x:0, y:0}
// 此时并不是给x,y设置默认值,而是给{x,y}整体赋值,通过解构赋值得到x,y的值,并不是默认值,所以此时若没有传递某个变量,则该变量将是undefined
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]
4 圆括号的使用
解构赋值解析并不简单。一个式子在解析到(解析不到)等号的时候才知道是表达式还是模式。所以在尽可能在模式中不放置圆括号
以下三种情况中不允许使用圆括号:
① 声明变量的语句
// 全部报错
let [(a)] = [1];
let {x: (c)} = {};
let ({x: c}) = {};
let {(x: c)} = {};
let {(x): c} = {};
let { o: ({ p: p }) } = { o: { p: 2 } };
② 函数参数中
函数参数也相当于声明变量
// 报错
function f([(z)]) { return z; }
// 报错
function f([z,(x)]) { return x; }
③ 赋值语句的模式
// 全部报错
// 整个模式放在括号中,将报错
({ p: a }) = { p: 42 };
([a]) = [5];
// 报错,部分模式放在括号中
[({ p: a }), { x: c }] = [{}, {}];
只有一种情况下可以使用圆括号:赋值语句的非模式部分
// ①赋值语句并非声明变量语句
// ②圆括号部分是非模式部分
//模式是取数组中的第一个元素
[(b)] = [3]; // 正确
// 模式是p而非d
({ p: (d) } = {}); // 正确
// 模式是取数组中的第一个元素
[(parseInt.prop)] = [3]; // 正确
5 解构赋值的用途
① 变量交换值
let x = 1;
let y = 2;
[x, y] = [y, x];
②函数返回多个参数
// 返回一个数组
function example() {
return [1, 2, 3];
}
let [a, b, c] = example();
// 返回一个对象
function example() {
return {
foo: 1,
bar: 2
};
}
let { foo, bar } = example();
③输入模块的指定方法
加载模块时,通常需要指定输入哪些方法,解构赋值将会使输入语句非常清晰
const { SourceMapConsumer, SourceNode } = require("source-map");
④提取json数据
let jsonData = {
id: 42,
status: "OK",
data: [867, 5309]
};
let { id, status, data: number } = jsonData;
console.log(id, status, number);
// 42, "OK", [867, 5309]
⑤函数参数的定义:可以有顺序或无顺序
// 参数是一组有次序的值
function f([x, y, z]) { ... }
f([1, 2, 3]);
// 参数是一组无次序的值
function f({x, y, z}) { ... }
f({z: 3, y: 2, x: 1});
⑥函数参数设置默认值
jQuery.ajax = function (url, {
async = true,
beforeSend = function () {},
cache = true,
complete = function () {},
crossDomain = false,
global = true,
// ... more config
} = {}) {
// ... do stuff
};
⑦遍历map结构,方便获取键值和键名
任何Iterator接口的对象,都可以使用for…of循环遍历。
map结构原生支持iterator接口,配合变量的解构赋值,获取键名和键值非常方便
const map = new Map();
map.set('first', 'hello');
map.set('second', 'world');
for (let [key, value] of map) {
console.log(key + " is " + value);
}
// first is hello
// second is world
// 获取键名
for (let [key] of map) {
// ...
}
// 获取键值
for (let [,value] of map) {
// ...
}