解构
ES6 新增了解构( destructuring ),它按照一定模式,从数组和对象中提取值,对变量进行赋值,这是将一个数据结构分解为更小的部分的过程。
对象解构
let { foo, bar } = { foo: "aaa", bar: "bbb" };
foo // "aaa"
bar // "bbb"
let { bar, foo } = { foo: "aaa", bar: "bbb" };
foo // "aaa"
bar // "bbb"
默认值
当你使用解构赋值语句时,如果所指定的本地变量在对象中没有找到同名属性,那么该变量会被赋值为 undefined 。
let node = {
type: "Identifier",
name: "foo"
};
let { type, name, value } = node;
console.log(type); // "Identifier"
console.log(name); // "foo"
console.log(value); // undefined
你可以选择性地定义一个默认值,以便在指定属性不存在时使用该值。若要这么做,需要在属性名后面添加一个等号并指定默认值。
let node = {
type: "Identifier",
name: "foo"
};
let { type, name, value = true } = node;
console.log(type); // "Identifier"
console.log(name); // "foo"
console.log(value); // true
赋值给不同的本地变量名
let node = {
type: "Identifier",
name: "foo"
};
let { type: localType, name: localName } = node;
console.log(localType); // "Identifier"
console.log(localName); // "foo"
type: localType 这种语法表示要读取名为 type 的属性,并把它的 值存储在变量 localType 上。该语法实际上与传统对象字面量语法相反,传统语法将名称放在冒号左边、值放在冒号右边;而在本例中,则是名称在右边,需要进行值读取的位置则被放在了左边。
数组解构
数组解构的语法看起来与对象解构非常相似,只是将对象字面量替换成了数组字面量。数组解构时,解构作用在数组内部的位置上,而不是作用在对象的具名属性上。
let [foo, [[bar], baz]] = [1, [[2], 3]];
foo // 1
bar // 2
baz // 3
let [ , , third] = ["foo", "bar", "baz"];
third // "baz"
let [x, , y] = [1, 2, 3];
x // 1
y // 3
只要等号两边的模式相同,左边的变量就会被赋予对应的值
剩余项
使用 ... 语法来将剩余的项目赋值给一个指定的变量
let [head, ...tail] = [1, 2, 3, 4];
head // 1
tail // [2, 3, 4]
let [x, y, ...z] = ['a'];
x // "a"
y // undefined
z // []
let colors = ["red", "green", "blue"];
let [...clonedColors] = colors;
clonedColors // ["red", "green", "blue"]
剩余项必须是数组解构模式中最后的部分,之后不能再有逗号,否则就是语法错误。
混合解构
对象与数组解构能被用在一起,以创建更复杂的解构表达式。在对象与数组混合而成的结构中,这么做便能准确提取其中你想要的信息片段。
let node = {
type: "Identifier",
name: "foo",
loc: {
start: {
line: 1,
column: 1
},
end: {
line: 1,
column: 4
}
},
range: [0, 3]
};
let {
loc: { start },
range: [ startIndex ]
} = node;
console.log(start.line); // 1
console.log(start.column); // 1
console.log(startIndex); // 0
字符串解构
字符串也可以解构赋值。这是因为此时,字符串被转换成了一个类似数组的对象。
const [a, b, c, d, e] = 'hello';
a // "h"
b // "e"
c // "l"
d // "l"
e // "o"
类似数组的对象都有一个length属性,因此还可以对这个属性解构赋值。
let {length : len} = 'hello';
len // 5
参数解构
当 JS 的函数接收大量可选参数时,一 个常用模式是创建一个 options 对象,其中包含了附加的参数。
// options 上的属性表示附加参数
function setCookie(name, value, options) {
options = options || {};
let secure = options.secure,
path = options.path,
domain = options.domain,
expires = options.expires;
// 设置 cookie 的代码
}
// 第三个参数映射到 options
setCookie("type", "js", {
secure: true,
expires: 60000
});
很多 JS 的库都包含了类似于此例的 setCookie() 函数。在此函数内, name 与 value 参 数是必需的,而 secure 、 path 、 domain 与 expires 则不是。此处虽然无须列出一堆额外的具名参数。但无法仅通过查看函数定义就判断出函数所期望的输入。参数解构能够更清楚地标明函数期望输入。它使用对象或数组解构的模式替代了具名参数。
function setCookie(name, value, { secure, path, domain, expires }) { // 设置 cookie 的代码
}
setCookie("type", "js", {
secure: true,
expires: 60000
});
解构参数在没有传递值的情况下类似于常规参数,它们会被设为 undefined 。同样参数解构也可以设置默认值。
用途
互换两个变量的值
let a = 1, b = 2;
[a, b] = [b, a ];
console.log(a); // 2
console.log(b); // 1
简洁,易读,语义清晰。
从函数返回多个值
// 返回一个数组
function example() {
return [1, 2, 3];
}
let [a, b, c] = example();
// 返回一个对象
function example() {
return {
foo: 1,
bar: 2
};
}
let { foo, bar } = example();
如果函数要返回多个值,我们只能将它们放在数组或对象里返回。有了解构赋值,取出这些值就非常方便。
提取 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});
解构赋值可以方便地将一组参数与变量名对应起来。