Sitemap

[JavaScript] 解構賦值 Destructuring Assignment

有一種變形金剛的既視感

12 min readSep 29, 2025

--

最後更新時間:2025–09–30

Press enter or click to view image in full size
這不是業配 | Photo by Igor Sporynin on Unsplash

前言

繼上一篇 [JavaScript] Optional Chaining Operator 可選串連運算子,這次打鐵趁熱接著再寫一篇 JS,解構賦值也是很常用、也滿好用的技巧,這次文章標題把中文放到英文名詞前面,語感上比較順,畢竟本部落格以中文為主,先帶出中文再附上英文似乎比較好,所謂的好其實毫無根據只是憑感覺 😎

話說第一次看到「解構賦值」這個名詞時,有個變形金剛的畫面掠過腦海,就像在電影中金字塔旁邊那隻大到靠杯的怪獸其實是由很多隻變形金剛組成,解構賦值有點像是「啪!」的一聲讓這隻大怪獸解構,變成好幾隻變形金剛讓他們各自行動,有種賦值的感覺。

說文解字

那就讓我們來看看 transformer 這個字,啊不是,來看看 Destructuring Assignment,這個字一開始看到覺得不太直觀,來好好拆解一下,首先依照慣例先看看字典怎麼說

結果字典查不到 destructuring,沒事,可以查得到 destruction(破壞),有點感覺了,查不到字典那就靠字根來研究:de-(拆解、相反)+ structure(結構)+ -ing(動名詞),因此是解構的意思也不意外。

assignment 的話,字典當然是有的:

a piece of work given to someone, typically as part of their studies or job

其實就是作業,但看這個解釋沒啥感覺,再看一個:

the process of giving a particular job or piece of work to someone, or of sending someone to a chosen place to do a job

就是分配(任務)、指派(人員),其實也是軟體工程所講的賦值,為這個變數賦予一個值

再重看一次 Destructuring Assignment,名詞前面的動名詞其實是形容詞的功能,所以這個字更像是「解構地賦予值」,把一個有結構的資料(陣列、物件)拆解成多個小部分然後賦值給變數。

那就讓我們來造個句幫助學習:

We unleashed the power of Destructuring Assignment to defeat the mighty Devastator beside the pyramid.

翻譯:我們使出解構賦值擊敗了金字塔旁的大魔王 Devastator(這絕對是個氣勢磅礡的造句)

解構賦值簡介

先來看看這個水果物件:

const fruit = {
apple: 10,
banana: 20,
cherry: 30,
}

如果想要創造水果價格的新變數且值為 fruit 內水果的值,原本可能要這樣寫:

const applePrice = fruit.apple
const bananaPrice = fruit.banana
const cherryPrice = fruit.cherry

而解構賦值可以這樣寫:

const { apple: applePrice, banana: bananaPrice, cherry: cherryPrice} = fruit

可以想像成,把水果們從 fruit 解構出來,並把他們的值賦予新的價格變數,所以在 console 印出會是:

console.log(applePrice) // 10
console.log(bananaPrice) // 20
console.log(cherryPrice) // 30

這一小段請容我直接使用在 [JavaScript] Optional Chaining Operator 可選串連運算子 寫過的格式。Destructuring Assignment 是在 ES2015 釋出的,有興趣可以去 ECMA 找 Standards,例如到這個頁面,找 ECMA-262, 6th edition, June 2015,看到 12.14.5 Destructuring Assignment 的章節。如果你好奇 ECMA、誰去制定等等問題,可以看這篇。

解構賦值 — 物件

看到這個小標就知道,解構賦值不只物件能用,稍後會再接著講陣列。物件如果要解構賦值有個重點,就是屬性名稱要能對應上,如果沒找到該屬性名稱那就會變 undefined,例如:

const fruit = {
apple: 10,
banana: 20,
cherry: 30,
}
const { date: datePrice} = fruit
console.log(datePrice) // undefined,因為 fruit 內沒有 date 這個屬性也就沒有值

接著來看一遍物件解構賦值的常見用法吧

// 基本用法
const fruit = { name: "Apple", year: 2025 };
const { name, year } = fruit;
console.log(name, year); // Apple 2025

// 變數改名,也就是上面簡介的例子
const { name: fruitName, year: fruitYear } = fruit;
console.log(fruitName, fruitYear); // Apple 2025

// 預設值,如果怕出現 undefined 也可以設個預設值
const { color = "red" } = fruit;
console.log(color); // red

// 巢狀物件
const fruit = {
name: "Apple",
profile: {
year: 2025,
country: "Japan"
}
};
const { profile: { country, year } } = fruit;
console.log(country, year); // Japan 2025

從最後一個巢狀物件的範例可以看到,順序不是物件解構賦值的重點,解構時 country 跟 year 的順序其實跟原物件內的順序不同,但可以正常賦值。

解構賦值 — 陣列

先看個例子馬上可以懂:

const fruit = [10, 20, 30]

// 原本要像下面這樣寫
// const applePrice = fruit[0]
// const bananaPrice = fruit[1]
// const cherryPrice = fruit[2]

// 解構賦值寫法
const [applePrice, bananaPrice, cherryPrice] = fruit
console.log(applePrice) // 10
console.log(bananaPrice) // 20
console.log(cherryPrice) // 30

相對於物件解構賦值時屬性名稱要能對應上,陣列解構賦值的重點是順序,這很好理解,因為陣列內每個元素就是用 index 去辨別的,其實邏輯都滿類似的,直接看範例:

// 基本用法
const fruit = [10, 20, 30];
const [apple, banana, cherry] = fruit;
console.log(apple, banana, cherry); // 10 20 30

// 跳過元素
const [apple, , cherry] = fruit;
console.log(apple, cherry); // 10 30

// 預設值
const [apple, banana, date = 40] = [10, 20];
console.log(apple, banana, date); // 10 20 40

// 互換變數
let apple = 10, banana = 20;
[apple, banana] = [banana, apple];
console.log(apple, banana); // 20 10

最後一個互換變數可以留意一下,如果把 let 改成 const 就會噴錯,因為不能改變常數的值

其他

這個區塊列幾個覺得可以參考的點。

1️⃣ null 不會觸發預設值

Get Johnny Fang’s stories in your inbox

Join Medium for free to get updates from this writer.

例如:

const { apple = 10 } = { apple: undefined } // apple 是 10
const { banana = 20 } = { banana: null} // banana 是 null

2️⃣ 其餘內容

也就是 JS 中常用的三個點「…」,可以把未解構的內容都包起來,例如:

// 物件
const { apple, ...others } = { apple: 10, banana: 20, cherry: 30 };
console.log(others); // { banana: 20, cherry: 30 }

// 陣列
const [apple, ...others] = [10, 20, 30];
console.log(others); // [20, 30]

有個點需要注意,這邊是其餘參數(Rest Parameter),跟展開運算子(Spread syntax)其實不一樣,想看更詳細的說明可以看這篇。

3️⃣ 可以在解構賦值時做運算嗎?不行

let fruit = {
apple: 10,
banana: 20,
cherry: 30,
};

// 不管是這樣寫
let { banana + 5: bananaPrice } = fruit;
// 或這樣寫
let { banana: bananaPrice + 5 } = fruit;

console.log(bananaPrice); // 都會噴出 SyntaxError 的錯誤

4️⃣ 一些奇怪的狀況

解構賦值可以對非物件或非陣列的對象使用嗎?可以,但要分情況。

字串(String)

字串可被當作「類陣列 (array-like)」,所以可以用陣列解構:

const [a, b, c, d] = "date";
console.log(a, b, c, d); // d a t e

也可以用 物件解構取屬性:

const { length } = "apple";
console.log(length); // 5

數字(Number)與布林值(Boolean)

基本上沒辦法像下面這樣直接一般使用:

const { apple } = true
console.log(apple) // undefined

const [banana] = 123
console.log(banana) // TypeError: 123 is not iterable

但可以取屬性:

const { toString: apple } = 123;
console.log(apple === Number.prototype.toString); // true

const { toString: banana } = true;
console.log(banana === Boolean.prototype.toString); // true

null 與 undefined

不能用,會噴錯

const { apple } = null;      // TypeError: Cannot destructure property 'apple' of 'null' as it is null.
const { apple } = undefined; // TypeError: Cannot destructure property 'apple' of 'undefined' as it is undefined.

個人使用情境與適用情境

我最常用的情境其實就是函式接收參數時,因為這樣呼叫函式時就不用按照固定順序傳參數XD,例如:

// 一般作法:參數要依照順序傳
function createFruit(name, year, country) {
return `${name} produced in ${country} in ${year}.`;
}

console.log(createFruit("Apple", 2025, "Japan"));
// Apple produced in Japan in 2025.

// 如果參數順序搞錯就會出問題
console.log(createFruit("Japan", 2025, "Apple"));
// Japan produced in Apple in 2025.
// 這啥啊!

改成用解構賦值寫法:

// 使用解構賦值:只要名稱對就行,順序無所謂
function createFruit({ name, year, country }) {
return `${name} produced in ${country} in ${year}.`;
}

// 傳參數時用物件,不管順序
console.log(createFruit({ name: "Apple", country: "Japan", year: 2025 }));
// Apple produced in Japan in 2025.

// 換個順序
console.log(createFruit({ country: "Japan", year: 2025, name: "Apple" }));
// Apple produced in Japan in 2025.
// 產出結果不能說很像只能說是一模一樣,讚

這邊簡單列出什麼時候適合與不適合使用解構賦值

🟢 適合使用

  • 減少重複的程式碼
  • 提高可讀性
  • 函式參數不在乎順序時
  • 一般 API 回傳值以物件居多,適合使用解構賦值,例如 React 在寫 API 相關 hook 時就滿好用的

❌ 不適合使用

  • 解構對象的型別不確定時有可能產生非預期錯誤
  • 解構對象有可能是 null 或 undefined
  • 需要計算或轉換才能賦值的話,解構賦值無法一步到位
  • 處理過程太過複雜,例如解構對象是很深的巢狀結構,或取值過程還要一堆條件

結尾

其實解構有兩種 pattern,綁定(Binding)與賦值(Assignment),前者我不熟、也幾乎沒用過,所以本篇都在談解構賦值,有興趣的朋友可以查一下,下面也附上參考資料,有些有提到綁定,可以看看,希望對大家有幫助。

參考文章

--

--