一、枚舉類型的基本定義與使用
在 TypeScript 中,我們可以使用枚舉類型(enum)來定義一組有標識意義的常量,它表示一種命名的整數常量集合。枚舉類型使用關鍵字 enum
來定義:
enum Direction { Up, Down, Left, Right } console.log(Direction.Up); // 0
枚舉類型默認從 0
開始遞增,所以 Direction.Up
的值為 0
,Direction.Down
的值為 1
,以此類推。我們也可以手動指定其中某些成員的值:
enum Direction { Up = 1, Down, Left = 2, Right } console.log(Direction.Up); // 1 console.log(Direction.Down); // 2 console.log(Direction.Left); // 2 console.log(Direction.Right); // 3
枚舉類型中的成員是只讀的,不能進行修改,而且在編譯後會被轉換成 JavaScript 代碼,真正運行時並不存在枚舉類型,只有常量值。
二、枚舉類型的高級使用
1. 字元串枚舉類型
枚舉類型的成員不僅可以是數字,也可以是字元串,這種類型被稱為字元串枚舉類型。字元串枚舉類型提供了更加直觀的可讀性:
enum Direction { Up = 'UP', Down = 'DOWN', Left = 'LEFT', Right = 'RIGHT' } console.log(Direction.Up); // UP
注意:需要在將字元串指定為枚舉成員的值時,需要使用類型斷言來將字元串類型轉換為枚舉類型:
enum Direction { Up = 'UP', Down = 'DOWN', Left = 'LEFT', Right = 'RIGHT' }
2. 常量枚舉類型
常量枚舉類型是在枚舉類型前加上 const
關鍵字來定義的,其成員只在編譯過程中起到作用,編譯後將直接展開為常量變數:
const enum Direction { Up = 'UP', Down = 'DOWN', Left = 'LEFT', Right = 'RIGHT' } console.log(Direction.Up); // UP
這樣做的好處是,當我們只是需要使用枚舉成員的值時,可以減少代碼體積和運行時的開銷。
3. 反向映射
枚舉成員不僅可以通過成員名訪問對應的值,還可以通過枚舉值反向查找對應的成員名。具體實現如下:
enum Direction { Up = 'UP', Down = 'DOWN', Left = 'LEFT', Right = 'RIGHT' } console.log(Direction['UP']); // Up
當枚舉成員的值沒有手動指定時,會對其進行反向映射,並在編譯後生成一個對象,用來實現枚舉值到枚舉名的反向映射:
var Direction; (function (Direction) { Direction[Direction["Up"] = 0] = "Up"; Direction[Direction["Down"] = 1] = "Down"; Direction[Direction["Left"] = 2] = "Left"; Direction[Direction["Right"] = 3] = "Right"; })(Direction || (Direction = {}));
三、案例分析:使用tsenum實現狀態機
狀態機是一種常見的計算機程序設計方法,它將計算機系統作為一組狀態和一組在這些狀態之間的轉換所組成的集合來表示。使用 tsenum 可以方便地實現狀態機。
下面以一個簡單的糖果機為例,來看看 tsenum 如何實現狀態機:
enum State { NO_QUARTER, // 沒有25分硬幣 HAS_QUARTER, // 有25分硬幣 SOLD, // 賣出糖果 SOLD_OUT // 糖果售完 } class GumballMachine { private state: State = State.NO_QUARTER; private count: number; constructor(count: number) { this.count = count; if (this.count > 0) { this.state = State.NO_QUARTER; } else { this.state = State.SOLD_OUT; } } public insertQuarter() { switch(this.state) { case State.NO_QUARTER: console.log('插入 25 分硬幣'); this.state = State.HAS_QUARTER; break; case State.HAS_QUARTER: console.log('已經有25分硬幣了,請不要重複插入'); break; case State.SOLD: console.log('請等待糖果掉落'); break; case State.SOLD_OUT: console.log('糖果已經售完'); break; } } public ejectQuarter() { switch(this.state) { case State.NO_QUARTER: console.log('您尚未插入25分硬幣'); break; case State.HAS_QUARTER: console.log('正在退回25分硬幣'); this.state = State.NO_QUARTER; break; case State.SOLD: console.log('已經出貨,無法退回25分硬幣'); break; case State.SOLD_OUT: console.log('糖果已經售完,無法退回25分硬幣'); break; } } public turnCrank() { switch(this.state) { case State.NO_QUARTER: console.log('請先插入25分硬幣'); break; case State.HAS_QUARTER: console.log('正在出售糖果...'); this.state = State.SOLD; this.dispense(); break; case State.SOLD: console.log('正在出售糖果,請耐心等待'); break; case State.SOLD_OUT: console.log('糖果已經售完,無法出售'); break; } } public dispense() { switch(this.state) { case State.NO_QUARTER: console.log('請先插入25分硬幣'); break; case State.HAS_QUARTER: console.log('請先轉動曲柄'); break; case State.SOLD: console.log('正在出貨,請等待'); this.count--; if (this.count > 0) { this.state = State.NO_QUARTER; } else { console.log('糖果已經售完'); this.state = State.SOLD_OUT; } break; case State.SOLD_OUT: console.log('糖果已經售完'); break; } } } let machine = new GumballMachine(10); machine.insertQuarter(); // 插入 25 分硬幣 machine.turnCrank(); // 正在出售糖果... machine.insertQuarter(); // 已經有25分硬幣了,請不要重複插入 machine.ejectQuarter(); // 正在退回25分硬幣 machine.turnCrank(); // 請先插入25分硬幣
上述案例演示了如何使用 tsenum 實現一個狀態機模型,可以通過狀態來判斷操作是否合法,並自動處理狀態轉換與狀態動作,使得代碼更加簡介、易於維護。
原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-tw/n/186490.html