枚舉(Enum)是一個命名元素的集合,用於取值被限定在一定范圍內的場景。
作用:將程序中不容易記憶的硬編碼,或者是在未來會發生改變的常量抽取出來,定義成枚舉類型,以此來提高程序的可讀性和可維護性
語法:
enum 枚舉類名 {
枚舉成員1, 枚舉成員2, 枚舉成員3... ... 枚舉成員n;
}
1、數字枚舉
使用枚舉可以定義一些有名字的數字常量,枚舉類型會被編譯成一個雙向映射的對象。枚舉成員會被賦值為從0開始遞增的數字,同時,也會被枚舉值到枚舉名進行反向映射
enum Days { Sun, Mon, Tue, Wed, Thu, Fri, Sat } console.log('Days', Days); // { // '0': 'Sun', // '1': 'Mon', // '2': 'Tue', // '3': 'Wed', // '4': 'Thu', // '5': 'Fri', // '6': 'Sat', // Sun: 0, // Mon: 1, // Tue: 2, // Wed: 3, // Thu: 4, // Fri: 5, // Sat: 6 // } console.log('Days[0]:', Days[0]); // Days[0]: Sun console.log('Days.Sun:', Days.Sun); // Days.Sun: 0 console.log('Days[Days.Sun]:', Days[Days.Sun]) // Days[Days.Sun]: Sun
上例中,枚舉類Days被編譯成了一個js對象,該對象首先以枚舉名為key,以數字常量為value,逐對新增;然后以數字常量為key,枚舉值為value,逐對新增。由此,建立了一個枚舉值和數字常量雙向映射的對象
var Days; (function (Days) { Days[Days["Sun"] = 0] = "Sun"; Days[Days["Mon"] = 1] = "Mon"; Days[Days["Tue"] = 2] = "Tue"; Days[Days["Wed"] = 3] = "Wed"; Days[Days["Thu"] = 4] = "Thu"; Days[Days["Fri"] = 5] = "Fri"; Days[Days["Sat"] = 6] = "Sat"; })(Days || (Days = {}));
默認情況下,第一個枚舉成員的值是0,后面的枚舉成員的值依次加1。也可以
enum Color1 { Red, Green, Blue }; enum Color2 { Red = 2, Green, Blue }; enum Color3 { Red, Green = 3, Blue }; enum Color4 { Red, Green, Blue = 0 }; // 不建議 enum Color5 { Red = -5, Green, Blue = 0 }; // 不建議 enum Color6 { Red = -6, Green, Blue }; console.log('Color1: ', Color1); console.log('Color2: ', Color2); console.log('Color3: ', Color3); console.log('Color4: ', Color4); console.log('Color5: ', Color5); console.log('Color6: ', Color6); // Color1: { '0': 'Red', '1': 'Green', '2': 'Blue', Red: 0, Green: 1, Blue: 2 } // Color2: { '2': 'Red', '3': 'Green', '4': 'Blue', Red: 2, Green: 3, Blue: 4 } // Color3: { '0': 'Red', '3': 'Green', '4': 'Blue', Red: 0, Green: 3, Blue: 4 } // Color4: { '0': 'Blue', '1': 'Green', Red: 0, Green: 1, Blue: 0 } // Color5: { '0': 'Blue', Red: -5, '-5': 'Red', Green: -4, '-4': 'Green', Blue: 0 } // Color6: { Red: -6, '-6': 'Red', Green: -5, '-5': 'Green', Blue: -4, '-4': 'Blue' }
2、字符串枚舉
字符串枚舉是不可以做雙向映射的,只有枚舉成員的名稱作為key
enum OrderStatus { Created = '已創建', Cancelled = '已取消' } // 編譯 var OrderStatus; (function (OrderStatus) { OrderStatus["Created"] = "\u5DF2\u521B\u5EFA"; OrderStatus["Cancelled"] = "\u5DF2\u53D6\u6D88"; })(OrderStatus || (OrderStatus = {})); console.log(OrderStatus); // { Created: '已創建', Cancelled: '已取消' }
3、異構枚舉
把數字枚舉和字符串枚舉混用,就形成了異構枚舉,這種方式很容易引起混淆,不推薦使用
enum Result { T, F = "不通過" } // 編譯 var Result; (function (Result) { Result[Result["T"] = 0] = "T"; Result["F"] = "\u4E0D\u901A\u8FC7"; })(Result || (Result = {})); console.log(Result); { '0': 'T', T: 0, F: '不通過' }
4、枚舉成員的特性
4-1、枚舉成員的值不可修改
Char.a = 6; // Cannot assign to 'a' because it is a read-only property
4-2、枚舉成員的分類
(1)、常量枚舉:沒有設置初始值,對已有枚舉成員的引用,常量的表達式
常量枚舉成員會在編譯時計算出結果,然后以常量的形式,出現在運行時環境
(2)、需要計算的非常量表達式
這些枚舉成員的值不會在編譯階段計算,而是保留到程序的執行階段
enum Char { // 常量枚舉成員 a, b = Char.a, c = 1 + 3, // 非常量枚舉成員 d = Math.random(), e = 'hello'.length } console.log(Char); // 編譯 var Char; (function (Char) { // 常量枚舉成員 Char[Char["a"] = 0] = "a"; Char[Char["b"] = 0] = "b"; Char[Char["c"] = 4] = "c"; // 非常量枚舉成員 Char[Char["d"] = Math.random()] = "d"; Char[Char["e"] = 'hello'.length] = "e"; })(Char || (Char = {})); // 運行 { '0': 'b', '4': 'c', '5': 'e', a: 0, b: 0, c: 4, d: 0.5257674738591782, '0.5257674738591782': 'd', e: 5 }
(3)、出現在非常量表達式后面的枚舉成員必須要賦初始值,否則會報錯(如下例中的 成員f )
enum Char { // 常量枚舉成員 a, b = Char.a, c = 1 + 3, // 非常量枚舉成員 d = Math.random(), e = 'hello'.length, f // 枚舉成員必須具有初始化表達式 }
5、常量枚舉
常量枚舉是在 enum關鍵字前使用 const 修飾符
特點:在編譯階段被移除
作用:當我們不需要一個對象,而需要對象的值,就可以使用常量枚舉,這樣就可以避免在編譯時生成多余的代碼和間接引用
const enum Month { Jan, Feb, Mar } // 編譯時,沒有任何輸出 console.log(Month); // "const" 枚舉僅可在屬性、索引訪問表達式、導入聲明的右側、導出分配或類型查詢中使用。
常量枚舉成員在使用的地方被內聯進來,且常量枚舉不可能有計算成員
const enum Directions { Up, Right, Down, Left } let directions = [Directions.Up, Directions.Right, Directions.Down, Directions.Left]; // 編譯 var directions = [0 /* Up */, 1 /* Right */, 2 /* Down */, 3 /* Left */]; console.log(directions); [ 0, 1, 2, 3 ]
const enum Directions { Up, Right, Down, Left, UpRight = 3 + 1, RightDown = Directions.Right + 2, LeftDown = 9, // RightUp = 'hello'.length // const enum member initializers can only contain literal values and other computed enum values } let directions = [ Directions.Up, Directions.Right, Directions.Down, Directions.Left, Directions.UpRight, Directions.RightDown, Directions.LeftDown ]; // 編譯 var directions = [ 0 /* Up */, 1 /* Right */, 2 /* Down */, 3 /* Left */, 4 /* UpRight */, 3 /* RightDown */, 9 /* LeftDown */ ]; console.log(directions); [ 0, 1, 2, 3, 4, 3, 9 ]
6、在某些情況下,枚舉和枚舉成員都可以作為單獨的類型存在
enum E { a, b } enum F { a = 0, b = 1 } enum G { a = 'apple', b = 'banana' } let e: E = 4; let f: F = 4; // console.log(e === f); // This condition will always return 'false' since the types 'E' and 'F' have no overlap. let e1: E.a = 3 let e2: E.b = 3 let e3: E.a = 3 // console.log(e1 === e2); // This condition will always return 'false' since the types 'E.a' and 'E.b' have no overlap console.log(e1 === e3); // true let g1: G = G.a let g2: G.a = G.a console.log(g1 === g2); // true
