iT邦幫忙

2026 iThome 鐵人賽

DAY 4
0
JavaScript

React 觀念架構:從js 基礎到Hook 底層邏輯 系列 第 4

DAY 4 解構賦值與展開運算子:寫出乾淨 State 操作語法的必修課

  • 分享至 

  • xImage
  •  

我們已經理解了 React 的「不可變性」與「閉包」。今天我們要來看兩個在 React 中出現率高達 90% 的 ES6 語法:解構賦值 (Destructuring) 與 展開運算子 (Spread Operator)。

這兩個語法不僅能讓程式碼變乾淨,更是操作 Immutable State(「資料不可變狀態) 的標準配備。

一、 解構賦值 (Destructuring)

解構賦值能讓我們直接將物件或陣列中的資料提取成獨立變數。

1. 陣列解構:useState

為什麼 useState 是寫成 const [count, setCount] = useState(0)?

因為 useState() 回傳的是一個包含兩個元素的陣列:[當前狀態, 更新函數]。

// 傳統寫法
const stateArray = useState(0);
const count = stateArray[0];
const setCount = stateArray[1];

//  陣列解構
const [count, setCount] = useState(0);

2. 物件解構:簡化 Props 接收

在接收組件 Props 時,解構賦值能省去大量重複的 props. 前綴,還能直接設定預設值 (Default Values) 與 重新命名 (Aliasing):

//  在參數列直接解構 Props 並賦予預設值
function UserCard({ name, role = 'Guest', age: userAge }) {
  return (
    <div>
      <h3>{name} ({role})</h3>
      <p>Age: {userAge}</p>
    </div>
  );
}

二、 展開運算子 (Spread Operator ...)

展開運算子(...)用來將物件或陣列的內容「展開」出來,這是實現 Immutability (不可變更新) 最常採用的語法。

1. 物件淺拷貝與屬性覆蓋

更新物件 State 時,我們使用 ... 複製原屬性,並在後面寫上要更新的屬性進行覆蓋:

const [user, setUser] = useState({ name: 'Alice', age: 20, city: 'Taipei' });

//  複製舊物件並覆蓋 age
const handleBirthday = () => {
  setUser({
    ...user, // 展開 name, age, city
    age: 21  // 覆蓋 age,回傳新物件參考
  });
};

要注意:後面的屬性會覆蓋前面的屬性!若順序寫反(例如 { age: 21, ...user }),結果會變成age先存 21 然後被 20 覆蓋掉

2. 陣列的不可變操作 (Immutable Array Methods)

在 React 中更新陣列 State 時,絕不能使用會修改原陣列的 push 或 unshift,應改用展開運算子建立新陣列:

const [items, setItems] = useState(['A', 'B']);

//  錯誤:push 會 直接修改原陣列
items.push('C');

//  正確:新增元素到末端
setItems([...items, 'C']); // ['A', 'B', 'C']

//  正確:新增元素到最前端
setItems(['Header', ...items]); // ['Header', 'A', 'B']

三、 其餘運算子 (Rest Operator ...)

雖然同樣是 ...,但當它出現在賦值或參數列表時,稱為「其餘運算子」,用來收集剩餘的資料。

實務應用:過濾特定屬性或透傳 Props

// 1. 從物件中剔除 password,保留其餘資料
const user = { id: 1, name: 'Alice', password: '123' };
const { password, ...safeUser } = user;
console.log(safeUser); // 結果會是{ id: 1, name: 'Alice' }

// 2. 組件 Props 透傳 (Rest Props Pass-through)
function CustomButton({ label, ...restProps }) {
  return (
    // restProps 包含了 onClick, disabled, className 等剩餘屬性
    <button className="btn" {...restProps}>
      {label}
    </button>
  );
}

上一篇
DAY 3 閉包 (Closure) 與作用域鏈:理解 Hook State 歷史紀錄的基石
下一篇
DAY 5 Array 高階函數 (map, filter, reduce) 在 JSX 與資料處理中的應用
系列文
React 觀念架構:從js 基礎到Hook 底層邏輯 7
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言