Typescript 实战 --- (2)枚举

枚举(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

 

posted @ 2020-01-10 16:05  rogerwu  阅读(1229)  评论(0编辑  收藏  举报