Blog
Blog copied to clipboard
[MDN] Destructuring assignment
Destructuring assignment
- 他的語法是一種 JavaScript expression, 可以直接
- 從
[]
取出項目值, - 從
{}
取出屬性值,
- 從
- 再放到獨立的變數
語法
let a, b, rest;
[a, b] = [10, 20];
console.log(a); // 10
console.log(b); // 20
[a, b, ...rest] = [10, 20, 30, 40, 50];
console.log(a); // 10
console.log(b); // 20
console.log(rest); // [30, 40, 50]
({ a, b } = { a: 10, b: 20 });
console.log(a); // 10
console.log(b); // 20
({ a, b, ...rest } = { a: 10, b: 20, c: 30, d: 40 });
console.log(a); // 10
console.log(b); // 20
console.log(rest); // {c: 30, d: 40}
說明
-
[]
和{}
目前有一種 literal expression 的寫法, 建立臨時資料.
const x = [1, 2, 3, 4, 5];
// const x = { a: 1, b: 2, c: 3 };
- 使用相似語法, 會在
=
的左側定義好要取出右側變數的甚麼值.
const x = [1, 2, 3, 4, 5];
const [a, b] = x;
console.log(a); // 1
console.log(b); // 2
const x = { a: 1, b: 2, c: 3 };
const { a, b } = x;
console.log(a); // 1
console.log(b); // 2
範例
陣列
基本
const hexes = ["#ff0000", "#ffff00", "#008000"];
const [red, yellow, green] = hexes;
console.log(red); // "#ff0000"
console.log(yellow); // "#ffff00"
console.log(green); // "#008000"
使用宣告好的變數
let a, b;
[a, b] = [1, 2];
console.log(a); // 1
console.log(b); // 2
預設值
- 如果取出的值是
undefined
, 則使用預設值.
let a, b;
[a = 5, b = 7] = [1];
console.log(a); // 1
console.log(b); // 7
交換變數值
- 過去我們要交換兩個變數的值, 需要一個暫存變數.
let 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]
用在函式回傳值
function f() {
return [1, 2];
}
let a, b;
[a, b] = f();
console.log(a); // 1
console.log(b); // 2
忽略你不要的回傳值
function f() {
return [1, 2, 3];
}
const [a, , b] = f();
console.log(a); // 1
console.log(b); // 3
const [c] = f();
console.log(c); // 1
- 忽略所有回傳值:
[, ,] = f();
用於陣列剩餘的項目
- 可以將陣列剩餘的項目取出來成為一個陣列:
const [a, ...b] = [1, 2, 3];
console.log(a); // 1
console.log(b); // [2, 3]
const [a, ...b,] = [1, 2, 3];
// SyntaxError: `...的項目` 不可以接逗號
// 因為 `...的項目` 後面不會有任何項目
將正規表示的結果取出
- 當正規表示法
exec()
找到符合後, 會回傳一個陣列.- 第一個項目是完全符合的字串,
- 接著的項目是每組小括號的符合字串
function parseProtocol(url) {
const parsedURL = /^(\w+)\:\/\/([^\/]+)\/(.*)$/.exec(url);
if (!parsedURL) {
return false;
}
console.log(parsedURL);
// ["https://developer.mozilla.org/en-US/docs/Web/JavaScript",
"https", "developer.mozilla.org", "en-US/docs/Web/JavaScript"]
const [, protocol, fullhost, fullpath] = parsedURL;
return protocol;
}
console.log(parseProtocol('https://developer.mozilla.org/en-US/docs/Web/JavaScript'));
// "https"
物件
基本
const user = {
id: 42,
is_verified: true,
};
const { id, is_verified } = user;
console.log(id); // 42
console.log(is_verified); // true
使用宣告好的變數
let a, b;
({ a, b } = { a: 1, b: 2 });
注意: 用於 object literal, 且沒有宣告, 你需要加上小括號
(...)
.
{a, b} = {a: 1, b: 2}
不合法, 因為左測的{a, b}
視為 block, 而不是 object literal.
({a, b} = {a: 1, b: 2})
合法, 因為等同於let {a, b} = {a: 1, b: 2}
(...)
的前面需要一個分號, 不然可能會把前一行當作函式執行.
使用新的變數名稱
const o = { p: 42, q: true };
const { p: foo, q: bar } = o;
console.log(foo); // 42
console.log(bar); // true
- 舉例,
const {p: foo} = o
是從物件o
取出一個叫做p
的屬性, 再給值到一個叫做foo
的區域變數.
預設值
- 如果取出的值是
undefined
, 則使用預設值.
const { a = 10, b = 5 } = { a: 3 };
console.log(a); // 3
console.log(b); // 5
使用新的變數名稱, 且提供預設值
- 可以同時
- 從物件取出屬性, 再給值到一個不同名稱的變數
- 如果取出的是
undefined
, 使用預設值
const { a: aa = 10, b: bb = 5 } = { a: 3 };
console.log(aa); // 3
console.log(bb); // 5
直接將物件傳入函式的設計
const user = {
age: 30,
displayName: "王阿明",
fullName: {
firstName: "小明",
lastName: "王",
},
};
function userAge({ age }) {
return age;
}
function whois({ displayName, fullName: { firstName: name } }) {
return `${displayName} 就是 ${name}`;
}
console.log(userAge(user)); // 30
console.log(whois(user)); // "王阿明 就是 小明"
函式參數的預設值
function drawChart({ size = "大", coords = { x: 0, y: 0 }, radius = 25 } = {}) {
console.log(size, coords, radius);
}
drawChart({
coords: { x: 18, y: 30 },
radius: 30,
});
// "大", { x: 18, y: 30 }, 30
drawChart();
// "大", { x: 0, y: 0 }, 25
如果你想要在呼叫函式時, 不用提供任何參數, 目前的設計很適合.
用於巢狀的物件和陣列
const metadata = {
title: "Scratchpad",
translations: [
{
locale: "de",
localization_tags: [],
last_edit: "2014-04-14T08:43:37",
url: "/de/docs/Tools/Scratchpad",
title: "JavaScript-Umgebung",
},
],
url: "/en-US/docs/Tools/Scratchpad",
};
let {
title: englishTitle, // 取 title 值, 再給值到 englishTitle
translations: [
{
title: localeTitle, // 取 title 值, 再給值到 localeTitle
},
],
} = metadata;
console.log(englishTitle); // "Scratchpad"
console.log(localeTitle); // "JavaScript-Umgebung"
用於 for-of
const people = [
{
name: "Mike Smith",
family: {
mother: "Jane Smith",
father: "Harry Smith",
sister: "Samantha Smith",
},
},
{
name: "Tom Jones",
family: {
mother: "Norah Jones",
father: "Richard Jones",
brother: "Howard Jones",
},
},
];
for (const {
name: n,
family: { father: f },
} of people) {
console.log("名字是: " + n + ", 父親是: " + f);
}
// "名字是: Mike Smith, 父親是: Harry Smith"
// "名字是: Tom Jones, 父親是: Richard Jones"
用於經過運算的屬性名稱
let key = "name";
let { [key]: myName } = { name: "王小明" };
// 如同 let { name: myName } = { name: "王小明" };
console.log(myName); // "王小明"
用於 rest 語法
- 可以將物件剩餘的屬性取出來成為一個物件.
let { a, b, ...rest } = { a: 10, b: 20, c: 30, d: 40 };
a; // 10
b; // 20
rest; // { c: 30, d: 40 }
用於不合法的變數名稱
const user = { "is-taiwanese": true };
const { "is-taiwanese": isTaiwanese } = user;
// 因為沒辦法寫成 const { is-taiwanese } = user;
console.log(isTaiwanese); // "true"
用於陣列和物件
- 你可以組合使用. 假設要
prop
的第三個項目, 且該項目物件的name
:
const props = [
{ id: 1, name: "Fizz" },
{ id: 2, name: "Buzz" },
{ id: 3, name: "FizzBuzz" },
];
const [, , { name }] = props;
console.log(name); // "FizzBuzz"
用於物件時, 也可能會取出其 prototype 物件中的屬性
let obj = { self: "123" };
obj.__proto__.prot = "456";
const { self, prot } = obj;
// self "123"
// prot "456" (從 prototype 取出)
瀏覽器相容
- 只有 IE 不支援, 其他瀏覽器都完全支援