解构数组
基本变量赋值
jsconst foo = ["one", "two", "three"];
const [red, yellow, green] = foo;
console.log(red); // "one"
console.log(yellow); // "two"
console.log(green); // "three"
解构比源更多的元素
在从赋值语句右侧指定的长度为 N 的数组解构的数组中,如果赋值语句左侧指定的变量数量大于 N,则只有前 N 个变量被赋值。其余变量的值将是未定义。
jsconst foo = ["one", "two"];
const [red, yellow, green, blue] = foo;
console.log(red); // "one"
console.log(yellow); // "two"
console.log(green); // undefined
console.log(blue); //undefined
交换变量
可以在一个解构表达式中交换两个变量的值。
没有解构的情况下,交换两个变量需要一个临时变量(或者用低级语言中的异或交换技巧)。
jslet a = 1;
let b = 3;
[a, b] = [b, a];
console.log(a); // 3
console.log(b); // 1
const arr = [1, 2, 3];
[arr[2], arr[1]] = [arr[1], arr[2]];
console.log(arr); // [1, 3, 2]
解析一个从函数返回的数组
从一个函数返回一个数组是十分常见的情况。解构使得处理返回值为数组时更加方便。
在下面例子中,要让 f() 返回值 [1, 2] 作为其输出,可以使用解构在一行内完成解析。
jsfunction f() {
return [1, 2];
}
const [a, b] = f();
console.log(a); // 1
console.log(b); // 2
忽略某些返回值
你可以忽略你不感兴趣的返回值:
jsfunction f() {
return [1, 2, 3];
}
const [a, , b] = f();
console.log(a); // 1
console.log(b); // 3
const [c] = f();
console.log(c); // 1
你也可以忽略全部返回值:
js[, ,] = f();
使用绑定模式作为剩余属性
数组解构的剩余属性可以是另一个数组或对象绑定模式。这允许你同时提取数组的属性和索引。
jsconst [a, b, ...{ pop, push }] = [1, 2];
console.log(a, b); // 1 2
console.log(pop, push); // [Function pop] [Function push]
jsconst [a, b, ...[c, d]] = [1, 2, 3, 4];
console.log(a, b, c, d); // 1 2 3 4
这些绑定模式甚至可以嵌套,只要每个剩余属性都在列表的最后。
jsconst [a, b, ...[c, d, ...[e, f]]] = [1, 2, 3, 4, 5, 6];
console.log(a, b, c, d, e, f); // 1 2 3 4 5 6
另一方面,对象解构只能有一个标识符作为剩余属性。
jsconst { a, ...{ b } } = { a: 1, b: 2 };
// SyntaxError: `...` must be followed by an identifier in declaration contexts
let a, b;
({ a, ...{ b } } = { a: 1, b: 2 });
// SyntaxError: `...` must be followed by an assignable reference in assignment contexts
从正则表达式匹配项中提取值
当正则表达式的 exec() 方法找到匹配项时,它将返回一个数组,该数组首先包含字符串的整个匹配部分,然后返回与正则表达式中每个括号组匹配的字符串部分。解构允许你轻易地提取出需要的部分,如果不需要,则忽略完整匹配。
jsfunction parseProtocol(url) {
const parsedURL = /^(\w+):\/\/([^/]+)\/(.*)$/.exec(url);
if (!parsedURL) {
return false;
}
console.log(parsedURL);
// ["https://developer.mozilla.org/zh-CN/docs/Web/JavaScript",
// "https", "developer.mozilla.org", "zh-CN/docs/Web/JavaScript"]
const [, protocol, fullhost, fullpath] = parsedURL;
return protocol;
}
console.log(
parseProtocol("https://developer.mozilla.org/zh-CN/docs/Web/JavaScript"),
);
// "https"
在任何可迭代对象上使用数组解构
数组解构调用右侧的迭代协议。因此,任何可迭代对象(不一定是数组)都可以解构。
jsconst [a, b] = new Map([
[1, 2],
[3, 4],
]);
console.log(a, b); // [1, 2] [3, 4]
不可迭代对象不能解构为数组。
jsconst obj = { 0: "a", 1: "b", length: 2 };
const [a, b] = obj;
// TypeError: obj is not iterable
只有在分配所有绑定之前,才会迭代可迭代对象。
jsconst obj = {
*[Symbol.iterator]() {
for (const v of [0, 1, 2, 3]) {
console.log(v);
yield v;
}
},
};
const [a, b] = obj; // Only logs 0 and 1
其余的绑定会提前求值并创建一个新数组,而不是使用旧的迭代器。
jsconst obj = {
*[Symbol.iterator]() {
for (const v of [0, 1, 2, 3]) {
console.log(v);
yield v;
}
},
};
const [a, b, ...rest] = obj; // Logs 0 1 2 3
console.log(rest); // [2, 3] (an array)