📋 目錄
如果你從 CSS 或 HTML 背景剛進入 JavaScript,剛看到
const { name, age } = person這樣的程式碼時,可能會想「這在搞什麼」。但當你學會解構賦值(destructuring)之後,你會發現過去那些「先宣告變數、再一個一個賦值」的四行程式碼,其實可以一行就完成。解構不是奇怪的語法糖——它是 JavaScript 裡,你一旦學會就再也回不去的語法。
什麼是解構賦值
解構賦值允許你從陣列或物件中提取值,一次性建立多個變數:
// 過去的方式:四行程式碼
const person = { name: '小明', age: 28, city: '台北' };
const name = person.name;
const age = person.age;
const city = person.city;
// 現代的方式:一行程式碼
const { name, age, city } = person;
同樣的邏輯也適用於陣列:
const colors = ['red', 'green', 'blue'];
// 過去的方式
const first = colors[0];
const second = colors[1];
// 現代的方式
const [first, second] = colors;
console.log(first); // 'red'
console.log(second); // 'green'
從 ESLint 警告學解構
ESLint 是 JavaScript 開發者的好朋友——它會在你寫出不那麼乾淨的程式碼時發出警告。很多時候,這些警告都在暗示你「該用解構了」。
常見警告:重複賦值同一物件的多個屬性
// ESLint 可能會警告:
// "Expected destructuring for 'person.name'"
// 醜陋的寫法
const user = getUser();
const name = user.name;
const email = user.email;
const avatar = user.avatar;
const score = user.score;
// 簡潔的寫法
const { name, email, avatar, score } = getUser();
常見警告:參數物件未解構
// 函式接收一個物件作為參數
// 但沒有解構
// 醜陋的寫法
function createUser(user) {
const name = user.name;
const email = user.email;
const role = user.role || 'user';
// ...
}
// 簡潔的寫法
function createUser({ name, email, role = 'user' }) {
// 參數直接解構,需要的值直接拿出來
// ...
}
這個「在參數中解構」的語法,剛開始可能不適應,但它非常強大——當你呼叫函式時,只要傳入一個物件就可以了:
// 呼叫時可以只提供部分屬性
const user = createUser({
name: '小明',
email: 'xiaoming@example.com',
// role 會使用預設值 'user'
});
物件解構:基礎
const book = {
title: '原子習慣',
author: 'James Clear',
year: 2018,
pages: 320,
};
// 基本語法
const { title, author } = book;
console.log(title); // '原子習慣'
console.log(author); // 'James Clear'
// 重新命名
const { title: bookTitle, author: writer } = book;
console.log(bookTitle); // '原子習慣'
console.log(writer); // 'James Clear'
// 預設值
const { title, price = 350 } = book;
console.log(price); // 350(因為 book 中沒有 price)
實用場景:從函式返回物件
// 函式返回一個物件
function getBrowserInfo() {
return {
name: 'Chrome',
version: 130,
platform: 'macOS',
};
}
// 使用解構提取需要的值
const { name, version } = getBrowserInfo();
console.log(`${name} ${version}`); // 'Chrome 130'
陣列解構:基礎
const rgb = [255, 128, 0];
// 基本語法
const [red, green, blue] = rgb;
console.log(red); // 255
console.log(green); // 128
console.log(blue); // 0
// 跳過某些元素
const [first, , third] = rgb;
console.log(first); // 255
console.log(third); // 0
// 其餘元素
const [head, ...rest] = rgb;
console.log(head); // 255
console.log(rest); // [128, 0]
// 交換變數(不需要暫存變數)
let a = 1;
let b = 2;
[a, b] = [b, a];
console.log(a); // 2
console.log(b); // 1
實用場景:React Hooks
// React 的 useState 返回一個陣列
const [count, setCount] = useState(0);
const [user, setUser] = useState(null);
const [loading, setLoading] = useState(true);
// useEffect 返回的 cleanup 函式很少用到,可以用 _ 忽略
const [count, setCount, _] = useState(0);
巢狀解構:處理複雜資料
const company = {
name: 'FrontEnd Corp',
address: {
city: '台北',
district: '信義區',
zip: '110',
},
employees: ['小明', '大華', '小美'],
};
// 巢狀物件解構
const {
name,
address: { city, district },
} = company;
console.log(city); // '台北'
console.log(district); // '信義區'
// 巢狀陣列解構
const {
employees: [firstEmployee, secondEmployee],
} = company;
console.log(firstEmployee); // '小明'
console.log(secondEmployee); // '大華'
實用場景:API 回應
// 假設 API 返回這樣的資料
const apiResponse = {
status: 'success',
data: {
user: {
id: 123,
profile: {
name: '小明',
avatar: 'https://example.com/avatar.jpg',
},
},
},
};
// 用巢狀解構提取需要的数据
const {
status,
data: {
user: {
profile: { name, avatar },
},
},
} = apiResponse;
console.log(status); // 'success'
console.log(name); // '小明'
console.log(avatar); // 'https://example.com/avatar.jpg'
綁定模式 vs 指派模式
綁定模式(Declaration)
// 使用 const 或 let 宣告新的變數
const { name, age } = person; // const 宣告
let { x, y } = point; // let 宣告
指派模式(Assignment)
// 已經存在的變數被賦予新值
let name, age;
({ name, age } = person); // 需要用圓括號包裹
// 因為 {} 在 JavaScript 中預設是程式碼區塊
這個語法細節很重要——如果你在 if 或其他區塊外直接寫 { name, age } = person,JavaScript 會把前面的 {} 當作區塊而不是解構。
解構的實際重構案例
重構前:冗長的 API 處理
// 重構前
function handleApiResponse(response) {
const data = response.data;
const user = data.user;
const userName = user.name;
const userEmail = user.email;
const userAvatar = user.avatar;
const meta = data.meta;
const totalPages = meta.totalPages;
const currentPage = meta.currentPage;
console.log(`${userName} (${userEmail})`);
console.log(`Page ${currentPage} of ${totalPages}`);
return {
userName,
userEmail,
userAvatar,
totalPages,
currentPage,
};
}
重構後:使用解構
// 重構後
function handleApiResponse({ data: { user: { name, email, avatar }, meta: { totalPages, currentPage } } }) {
console.log(`${name} (${email})`);
console.log(`Page ${currentPage} of ${totalPages}`);
return { name, email, avatar, totalPages, currentPage };
}
一行參數搞定——所有需要的值直接從龐大的回應物件中被解構出來。
與其配套的語法:展開運算子
解構經常與展開運算子(spread operator)一起使用:
const { name, ...rest } = person;
console.log(name); // '小明'
console.log(rest); // { age: 28, city: '台北', ...其他屬性 }
// 合併物件
const defaults = { theme: 'light', language: 'zh-TW' };
const userPrefs = { theme: 'dark' };
const merged = { ...defaults, ...userPrefs };
// { theme: 'dark', language: 'zh-TW' }
結語:從「看起來很奇怪」到「無法回頭」
解構賦值是那種「剛開始覺得怪,學會之後停不下來」的語法。一旦你開始用 const { name, email } = user 取代 const name = user.name; const email = user.email;,你就會開始到處想用解構。
實用的建議:
- 函式參數:盡可能解構,你可以一眼看出函式需要什麼值
- API 回應:用巢狀解構提取你需要的一小部分
- React Hooks:直接從返回的陣列解構,你一直在用這個模式
你不需要記住所有的語法——在實際寫的時候,ESLint 和 TypeScript 會提醒你「這裡可以用解構」。那個警告,其實是個很好的提示。
延伸閱讀
- ES6 語法完整教學 — ES6+ 新語法總覽
- TypeScript 教學 — TypeScript 入門指南
本文是「2026 JavaScript 實用語法」系列文章之一。