這篇文章跟大家介紹一下TypeScript中Enum(枚舉)語法,聊聊Enum的基本用法,如何使用原生JavaScript來實現Enum。
Enum 是TypeScript 中新增的語法,也稱為枚舉,一般用它來管理多個相同系列的常數(即不能被修改的變數),用於狀態的判斷。
在Web 中比較常見的狀態判斷,是在處理請求時,要針對不同的回應狀態碼做對應的處理:
const handleResponseStatus = (status: number): void => { switch (status) { case 200: // 请求成功时 // Do something... break; case 400: // 请求失败时 // Do something... break; default: throw (new Error('No have status code!')); } };
但因為回應狀態碼都是預先定義好的,所以沒什麼爭議,程式碼寫成這樣看也很正常,但是如果後端在伺服器發生錯誤時自訂了一些編碼,並告訴前端,這些程式碼都代表什麼錯誤,那麼上面的函數可能會變成這樣:
const handleWrongStatus = (status: string): void => { switch (status) { case 'A': // Do something... break; case 'B': // Do something... break; case 'C': // Do something... break; default: throw (new Error('No have wrong code!')); } };
如果是這種程式碼,別說是剛接手的人,就算是你自己兩星期前寫的,恐怕不去翻文檔也想不起它們都代表什麼了吧。
但如果善用 Enum ,就可以避免上述發生的情況。
先來看看Enum 該怎麼定義,它和Object 的用法很像:
enum requestStatusCodes { error, success, }
不需要在內容與名稱之間加等號,直接在大括號內敘述該Enum 中具有哪些變量,與其說是變量,不如說是常數更恰當些,因為在Enum 中的值是不可修改的,所以也不必擔心這些定義好的規則會在程式碼中執行的過程中發生改變,導致執行錯誤。
而既然 Enum 是用來定義同一個系列常數的,那麼這些常數應該都能維護特定的值。沒錯,在 Enum 中的每個常數,都可以透過 =
來指定具體的值 。
但如果是像前面的requestStatusCodes
,沒有為error
或success
指定具體的值也不會出錯,因為TypeScript 會從0
開始自動遞增定義值,所以簽章的requestStatusCodes
會和下面的結果相同:
enum requestStatusCodes { error = 0, success = 1, }console.log(requestStatusCodes.error) // 0 console.log(requestStatusCodes.success) // 1
除了數字外,也可以定義為字串:
enum requestWrongCodes { missingParameter = 'A', wrongParameter = 'B', invalidToken = 'C', }console.log(requestWrongCodes.wrongParameter) // 'B'
當然也可以在一個enum 中設定不同的類型,但這樣一點意義都沒有:
enum requestStatusCodes { error = 0, success = 'OK', }
了解基本的Enum 怎麼定義後,接著就來改寫前面程式碼中的handleResponseStatus
和handleWrongStatus
,讓它們在語意上更能明確。
先用Enum 定義兩者的狀態描述:
enum requestStatusCodes { error = 400, success = 200, } enum requestWrongCodes { missingParameter = 'A', wrongParameterType = 'B', invalidToken = 'C', }
然後修改handleResponseStatus
和handleWrongStatus
中的Switch 判斷:
const handleResponseStatus = (status: number): void => { switch (status) { case requestStatusCodes.success: // Do something... break; case requestStatusCodes.error: // Do something... break; default: throw (new Error('No have status code!')); } }; const handleWrongStatus = (status: string): void => { // 如果觉得 requestWrongCodes.missingParameter 太长了,也可以用以下方式: const { missingParameter, wrongParameterType, invalidToken, } = requestWrongCodes; switch (status) { case missingParameter: // Do something... break; case wrongParameterType: // Do something... break; case invalidToken: // Do something... break; default: throw (new Error('No have wrong code!')); } };
修改後的程式碼就變得直觀多了,因為狀態碼都被放到了Enum 中統一管理,所以就能用常量名來代表它們,之後不管過了多久,可以明確的知道這裡再做什麼,甚至連註解或文件都不用寫了,因為程式碼就是最好的文件。
善用 Enum 能讓程式碼絕對是不可或缺的,但就算沒使用 TypeScript 也別灰心,因為 TypeScript 最終會被轉換為 JavaScript ,那來看看如何直接用 JavaScript 實作 Enum 吧!
前面說過 Enum 很像 Object ,如果研究一下 Enum 被編譯成 javascript 之後的程式碼,就會發現還真的是 Object。
Enum 被編譯後會變成Key 和Value 反向對應的對象,這樣看起來非常簡單,為了方便使用,下面把它的編譯方式寫成一個函數:
const newEnum = (descriptions) => { const result = {}; Object.keys(descriptions).forEach((description) => { result[result[description] = descriptions[description]] = description; }); return result; }; const responseStatus = newEnum({ error: 400, success: 200, }); // { '200': 'success', '400': 'error', error: 400, success: 200 } console.log(responseStatus);
雖然得到的結果相同,但是喪失了Enum 中最可貴的常數特色,如果不能讓它變成不可修改,那就有可能會在代碼裡不經意地改動它,導致執行結果可能出錯,於是可以在最後利用Object.freeze()
,讓外部操作無法新增、刪除或重新定義任何Property :
const newEnum = (descriptions) => { const result = {}; Object.keys(descriptions).forEach((description) => { result[result[description] = descriptions[description]] = description; }); return Object.freeze(result); }; const responseStatus = newEnum({ error: 400, success: 200, }); // 即使不小心修改了 responseStatus['200'] = 'aaaaaaaa'; // 仍然是 { '200': 'success', '400': 'error', error: 400, success: 200 } console.log(responseStatus);
這樣就能簡單在JavaScript 中實作Enum 了。
從前面的JavaScript 程式碼中可以看到Enum 編譯過後會變成Key 和Value 互相對應的Object ,也就是說不管是用Key 還是Value 都可以取出對應的值,
但如果用const
宣告Enum ,編譯之後就不會產生Object。
直接看例子,假設我把responseState
用const
重新生命,而且也是以handleResponseStatus
使用該Enum 做判斷:
enum responseStatus { error = 400, success = 200, } const handleResponseStatus = (status: number): void => { switch (status) { case responseStatus.success: console.log('请求成功!'); break; case responseStatus.error: console.log('请求失败!'); break; default: throw (new Error('No have status code!')); } };
看起來一切正常,不過在編譯後的JavaScript 中,會發現Enum 並沒有產生Object ,而是直接用const
宣告在Enum 中的值。
用const
宣告Enum 有幾個好處:
假設要用到的Enum 非常多,執行時就會不停地使用IIFE 產生Object 將Key 和Value 綁定到Object,會造成一些效率上的損失,也會增加內存,但是const
並不會產生Object ,也就不會有以上的問題。
就算到的 Enum 不多,判断时也需要一直从 Object 中找出对应的值,而如果是用 const
声明 Enum ,在编译成 JS 时就将声明的值直接放入判断中。
不过这样也就没法从 Enum 中反向取值了,因为它并不会产生对象:
const enum responseStatus { error = 400, success = 200, }// 会出错,因为已经没有对象可供查找了 console.log(responseStatus[400])// 但这个不会有问题,因为编译的时候会直接填值 console.log(responseStatus.error)// 编译后: // console.log(400)
更多编程相关知识,请访问:编程入门!!
以上是聊聊TypeScript中Enum(枚舉)的用法的詳細內容。更多資訊請關注PHP中文網其他相關文章!