解構
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});
解構賦值可以方便地將一組參數與變量名對應起來。