面試高頻考點:使用物件(或 Map/Set)實現陣列去重。本文逐行拆解經典 unique 函式,幫助理解「為何這樣寫能去重」。
function unique(arr) {
var obj = {};
var uniAfter = [];
for (var i = 0; i < arr.length; i++) {
if (!obj[arr[i]]) {
uniAfter.push(arr[i]);
obj[arr[i]] = 1;
}
}
return uniAfter;
}
假設輸入 arr = [1, 2, 2, 3, 1]:
| 迴圈輪次 | arr[i] | obj[arr[i]] 當前值 | !obj[arr[i]] 結果 | 動作 | obj 狀態 | uniAfter 狀態 |
|---|---|---|---|---|---|---|
| 0 | 1 | undefined | true | push 1, obj[1]=1 | {1:1} | [1] |
| 1 | 2 | undefined | true | push 2, obj[2]=1 | {1:1, 2:1} | [1,2] |
| 2 | 2 | 1 | false | 略過 | {1:1, 2:1} | [1,2] |
| 3 | 3 | undefined | true | push 3, obj[3]=1 | {1:1, 2:1, 3:1} | [1,2,3] |
| 4 | 1 | 1 | false | 略過 | {1:1, 2:1, 3:1} | [1,2,3] |
obj[key] 若不存在回傳 undefined,在 if 判斷中為 falsy;賦值後為 1(truthy),再次遇到同值時 !1 === false,達到去重。arr[i] 會隱式轉字串。故 1 與 "1" 視為相同,{} 與 [] 也會轉為 "[object Object]" 導致誤判,不適合含物件/陣列的複雜資料。// Set 去重(不保證順序,但現代引擎保持插入順序)
const unique = arr => [...new Set(arr)];
// Map 保留首次出現順序,支援任意類型鍵值
const unique = arr => {
const seen = new Map();
return arr.filter(item => !seen.has(item) && seen.set(item, 1));
};
NaN 在物件鍵中會被轉為 "NaN",可正常去重;+0 與 -0 視為相同。理解底層機制,才能在面對變體需求(如保留最後一次出現、自定義比較器)時靈活改寫,而非死記硬背。