[Day18]:小鴨鴨排隊游 - Enum列舉
小鴨鴨排隊游
2022搞笑諾貝爾物理獎:小鴨游泳排隊跟在媽媽後面,「加速相位」寫程式也一樣,排排隊寫起來更快。───────────────────────── By Opshell
目標:Enum(列舉)
在JS 中 如果要判斷很多狀態 通常會用各種方式做紀錄, 註解、物件等:
// javascript Code
/** gender
* 1 = Man
* 2 = Woman
* 3 = other
*/
const gender = {
'1': 'Man',
'2': 'Woman',
'3': 'Other'
};
2
3
4
5
6
7
8
9
10
11
過程:
Enum基礎
在TS中提供了
Enum(列舉)
, 用來管理多個同系列的常數(不可修改的變數, 語法:enum 列舉名稱 {列舉內容}
, ※Enum(列舉)
名稱沒有規定要純大寫(只是習慣)typescriptenum GENDER { MAN, WOMAN, OTHER, } const Opshell = GENDER.MAN; const Patty = GENDER[1]; console.log(Opshell); // 0 console.log(Patty); // WOMAN
1
2
3
4
5
6
7
8
9
10
11※ 沒有賦值的情況下,TS會自動從0開始賦值。 也接受只賦值部分的情況:
typescriptenum GENDER { MAN = 2, WOMAN, // 3 OTHER, // 4 } const Opshell = GENDER.MAN; const Patty = GENDER[1]; console.log(Opshell); // 2 console.log(Patty); // undefined
1
2
3
4
5
6
7
8
9
10
11上面這個情況,TS會依照你賦值的後面繼續遞增,如果有重複的, 後來者覆蓋前者(會出現不經意的坑),所以不推薦這樣使用, 要馬全給,要馬不給。
Enum(列舉)
的值也是能計算的:typescriptenum FEATURE { None = 0, O_BLOOD = 1 << 0, // 轉成10進制會是 1 BRUNETTE = 1 << 1, // 2 BROWN_EYE = 1 << 2, // 4 EAGLE_NOSE = 1 << 3, // 8 UNIVERSAL_ASIA = BRUNETTE + BROWN_EYE // 6 }
1
2
3
4
5
6
7
8當然
Enum(列舉)
除了數字外,也可以用字串當值 某方面來說更能讓人讀懂程式碼:typescriptenum GENDER { MAN = 'DNA=XY', WOMAN = 'DNA=XX', OTHER = 'have a different identity.' }
1
2
3
4
5※ 數字、字串混用也可以,只是這樣很亂, 常數內容反而很不明確,很少這樣用,除非你確實需要。
實務應用
Enum(列舉、枚舉)
實務中比較常見的用法是, 配合型別檢測(Type Guard)
中的一種模式,Discriminated unions(集合鑑別)
處理請求,針對不同的Response status codes(狀態代碼)
typescriptenum STATUS_LIST { SUCCESS = 200, ERROR = 400, } /** 定義多個不同的 interface, * 但這些 interface 中都會有一個共同的欄位"status" * 以此欄位來判斷物件中會有其他哪些屬性。 */ interface iSuccessResp { status: STATUS_LIST.SUCCESS; data: unknown; } interface iErrorResp { status: STATUS_LIST.ERROR; errorCode: number; message: string; } // 利用 Union 的方式產生 Union Type type tResp = iSuccessResp | iErrorResp; /** 不要在函式參數的地方做物件的解構, * 不要這樣:({status, data, errorCode, message}: tResp) * 需要的話,可以在 switch case 判斷完後再來解構 */ const parseResponse = (resp: tResp) => { /** 當然Enum也可以解構來使用: * const { OK, ERROR } = STATUS_LIST; */ switch (resp.status) { // 透過 narrow 可以確定這裡的 resp 是哪個型別 case STATUS_LIST.SUCCESS: { const { data } = resp; // 這邊才解構 return data; } case STATUS_LIST.ERROR: { const { errorCode, message } = resp; // 這邊才解構 return `${errorCode}:${message}`; } } };
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42※ 在上面範例中
Enum(列舉)
的宣告方式, 編譯過後會變成 key 和 value 互相對應的Object
, 不管是用 key 還是 value 都可以取出對應的值, 這就是Enum
的反向對映
特性, 原理是使用IIFE(立即執行函式)
產生Object
將 key 和 value 綁定起來, 但是IIFE(立即執行函式)
會造成一些效能上的耗損,也會增加記憶體消耗,Enum(列舉)
數量一多,效能會變差。※ 要解決上面這個問題,在不需要key value互相對應的情況下 可以像這樣:
typescriptconst enum STATUS_DESCRIPTION { OK = 'Success', Error = 'Fail', };
1
2
3
4※ 這就是所謂的
const enum(常數列舉)
, 這種方法就不能用計算式賦值,只能使用固定值, 編譯階段也會被刪除,所以不會互相對應, 不會產生物件,性能就高了。
小結:
學習完所謂的
Enum(列舉)
, 會發現原生的JavaScript Object 就能簡易的實現大部分的功能,Enum(列舉)
最主要的差別就是提高了他的可讀性, 更易於管理。