ES6 Set vs. Map
Set 和 Map 是 ES6 引入的兩種資料結構,它們用來處理資料集合,但用途和特性不同。以下是它們的詳細比較:
1. Set
-
定義:Set 是一個儲存唯一值的集合,任何型別的值(原始值或物件)都可以儲存,但每個值只會出現一次。
-
特點:
-
去重複:自動移除重複的值。
-
無鍵值對:只有值,沒有鍵。
-
迭代順序:值的插入順序會被保留,迭代時按插入順序返回。
-
用途:適合用來儲存不重複的資料,例如去重陣列、檢查值是否存在。
-
大小:透過 size 屬性取得元素數量。
-
常用方法:
-
add(value):新增值。
-
has(value):檢查值是否存在。
-
delete(value):刪除值。
-
clear():清空所有值。
-
forEach(callback):迭代每個值。
-
可使用 for...of 或展開運算子 (...) 迭代。
-
-
2. Map
-
定義:Map 是一個儲存鍵值對的集合,鍵和值可以是任何型別(原始值或物件)。
-
特點:
-
鍵值對:每個元素由鍵和值組成,鍵是唯一的。
-
靈活的鍵:鍵可以是物件、函式等,而不僅限於字串或符號(不像普通物件)。
-
迭代順序:鍵值對的插入順序會被保留。
-
用途:適合用來儲存有鍵值對應關係的資料,例如字典、物件的增強版。
-
大小:透過 size 屬性取得鍵值對數量。
-
常用方法:
-
set(key, value):新增或更新鍵值對。
-
get(key):取得指定鍵的值。
-
has(key):檢查鍵是否存在。
-
delete(key):刪除指定鍵值對。
-
clear():清空所有鍵值對。
-
forEach(callback):迭代每個鍵值對。
-
可使用 for...of 迭代鍵值對、鍵或值。
-
-
主要差異
特性 | Set | Map |
---|---|---|
資料結構 | 僅儲存值(無鍵) | 儲存鍵值對 |
唯一性 | 值必須唯一 | 鍵必須唯一,值可重複 |
鍵的型別 | 無鍵 | 鍵可以是任何型別(包括物件) |
用途 | 去重複、檢查值是否存在 | 鍵值對應、儲存結構化資料 |
查詢方法 | has(value) | has(key)、get(key) |
大小 | size | size |
在 React 中的使用範例
以下是一個完整的 React 專案範例,展示如何在 React 組件中使用 Set 和 Map,並以簡單的 UI 呈現它們的功能。這個範例會建立一個應用程式,讓使用者輸入資料,展示 Set 的去重功能和 Map 的鍵值對管理。
範例需求
-
使用 Set 來儲存不重複的使用者輸入名稱。
-
使用 Map 來儲存名稱和對應的輸入次數(鍵值對)。
-
提供輸入框和按鈕,讓使用者新增資料,並顯示結果。
完整程式碼
import React, { useState } from "react";
function App() {
// 狀態管理
const [inputName, setInputName] = useState(""); // 輸入框的值
const [nameSet, setNameSet] = useState(new Set()); // 使用 Set 儲存不重複名稱
const [nameMap, setNameMap] = useState(new Map()); // 使用 Map 儲存名稱和次數
// 處理輸入框變更
const handleInputChange = (e) => {
setInputName(e.target.value);
};
// 處理新增按鈕
const handleAddName = () => {
if (inputName.trim() === "") {
alert("請輸入名稱!");
return;
}
// 更新 Set
const newSet = new Set(nameSet); // 複製現有 Set
newSet.add(inputName); // 新增名稱到 Set(自動去重)
setNameSet(newSet);
// 更新 Map
const newMap = new Map(nameMap); // 複製現有 Map
const currentCount = newMap.get(inputName) || 0; // 取得當前次數,預設為 0
newMap.set(inputName, currentCount + 1); // 更新次數
setNameMap(newMap);
// 清空輸入框
setInputName("");
};
// 渲染 Set 的內容
const renderSetContent = () => {
return Array.from(nameSet).map((name, index) => (
<li key={index}>{name}</li>
));
};
// 渲染 Map 的內容
const renderMapContent = () => {
return Array.from(nameMap).map(([name, count], index) => (
<li key={index}>
{name}: {count} 次
</li>
));
};
return (
<div style={{ padding: "20px" }}>
<h1>Set 與 Map 範例</h1>
{/* 輸入框和按鈕 */}
<div>
<input
type="text"
value={inputName}
onChange={handleInputChange}
placeholder="輸入名稱"
/>
<button onClick={handleAddName}>新增</button>
</div>
{/* 顯示 Set 結果 */}
<div>
<h2>不重複名稱 (Set)</h2>
<p>總數量: {nameSet.size}</p>
<ul>{renderSetContent()}</ul>
</div>
{/* 顯示 Map 結果 */}
<div>
<h2>名稱與次數 (Map)</h2>
<p>總數量: {nameMap.size}</p>
<ul>{renderMapContent()}</ul>
</div>
</div>
);
}
export default App;
程式碼說明
-
狀態管理:
-
使用 useState 管理輸入框的值 (inputName)、儲存名稱的 Set (nameSet) 和儲存名稱與次數的 Map (nameMap)。
-
因為 Set 和 Map 是物件,直接修改不會觸發 React 重新渲染,所以我們使用複製的方式更新它們。
-
-
處理輸入:
-
handleInputChange:更新輸入框的值。
-
handleAddName:
-
檢查輸入是否為空。
-
更新 Set:使用 add 新增名稱,自動去重。
-
更新 Map:使用 set 更新名稱的計數,若名稱不存在則初始化為 0。
-
清空輸入框。
-
-
-
渲染結果:
-
renderSetContent:將 Set 轉為陣列並渲染為清單,顯示不重複的名稱。
-
renderMapContent:將 Map 轉為陣列,顯示名稱和對應的輸入次數。
-
使用 size 屬性顯示 Set 和 Map 的元素數量。
-
-
UI 設計:
-
包含一個輸入框和按鈕,讓使用者輸入名稱。
-
顯示兩個區塊:一個展示 Set 的不重複名稱,另一個展示 Map 的名稱和次數。
-
使用場景建議
-
使用 Set:
-
當你需要儲存不重複的值,例如:
-
過濾重複的標籤(tags)。
-
儲存唯一的使用者 ID。
-
檢查某個值是否已經存在。
-
-
範例:移除陣列中的重複元素:
const array = [1, 2, 2, 3, 3, 4];
const uniqueArray = [...new Set(array)]; // [1, 2, 3, 4]
-
-
使用 Map:
-
當你需要儲存鍵值對,且鍵可能是複雜型別(例如物件),例如:
-
儲存使用者的設定(鍵是使用者物件,值是設定)。
-
記錄每個項目的計數或屬性。
-
-
範例:以物件作為鍵:
const map = new Map();
const keyObj = { id: 1 };
map.set(keyObj, "使用者資料");
console.log(map.get(keyObj)); // '使用者資料'
-
常見問題
-
為什麼不用陣列或物件代替 Set 和 Map?
-
陣列:不自動去重,檢查值是否存在需要遍歷,效率較低(O(n))。
-
物件:鍵只能是字串或符號,無法直接使用物件作為鍵,且沒有內建的 size 屬性。
-
Set 和 Map 提供更高的效率(大多數操作為 O(1))和更靈活的鍵型別。
-
-
在 React 中更新 Set 和 Map 時為什麼要複製?
- React 的狀態更新需要不可變性(immutability)。直接修改 Set 或 Map 不會觸發重新渲染,因此需要創建新實例。
-
Set 和 Map 的效能如何?
-
兩者內部使用哈希表,查詢和插入操作通常為 O(1)。
-
比陣列的 includes(O(n))或物件的鍵檢查更高效。
-
總結
-
Set:適合處理不重複的值,簡單高效,常用於去重或快速檢查。
-
Map:適合儲存鍵值對,鍵型別靈活,適用於結構化資料。
-
在 React 中,使用 Set 和 Map 時,記得複製實例以確保狀態更新正確。