内容简介:枚举,就是按照枚举值的类型,把枚举分为数值枚举,字符串枚举以及异构枚举。此外,还有特殊的联合枚举,以及常量枚举和环境枚举声明了4个方向常量,值分别为
一.简介
枚举,就是 一组具名常量 :
Enums allow us to define a set of named constants.
按照枚举值的类型,把枚举分为数值枚举,字符串枚举以及异构枚举。此外,还有特殊的联合枚举,以及常量枚举和环境枚举
二.数值枚举
enum Direction { Up, // 0 Down, // 1 Left, // 2 Right, // 3 }
声明了4个方向常量,值分别为 0, 1, 2, 3
。这些值是自动初始化并自增而来的,想要从指定数值开始也很容易:
enum Direction { Up = 1, // 1 Down, // 2 Left, // 3 Right, // 4 }
枚举值的这种 自增机制 相当省事,毕竟在大多数场景下我们并不关心具体的枚举值,只要保证唯一,能与其它同类枚举值区分开即可:
function turn(direction: Direction): void { switch (direction) { case Direction.Up: console.log('Turn up now'); break; case Direction.Down: console.log('Turn down now'); break; // ... default: console.log('Turn around here'); } }
自增要有一个起始值,称之为initializer,因此,类似这样的场景下枚举值无法完成初始化:
function getStartValue() { return 1; } enum E { A = getStartValue(), // 报错 Enum member must have initializer. B, }
无法在编译时确定自增起始值,就没办法通过自增机制自动填充枚举值。具体的,没被显式初始化的枚举值,要么最先出现,要么出现在在其它数值常量枚举值之后
反向映射
TypeScript里可用通过枚举值取到对应枚举常量名,这种特性称之为反向映射(reverse mapping),例如:
enum Direction { Up, Down, Left, Right, } // 正向 按名取值 console.log(Direction.Down); // 1 // 反向 按值取名 console.log(Direction[1]); // 'Down'
因为在声明数值枚举的同时建立了反向关系:
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 = {})); // ["0", "1", "2", "3", "Up", "Down", "Left", "Right"] console.log(Object.keys(Direction));
但 仅限于数值枚举 (为了弥补数值枚举在运行时的可读性缺陷),其它类型的枚举并不建立反向关系
三.字符串枚举
enum Direction { Up = "UP", Down = "DOWN", Left = "LEFT", Right = "RIGHT", }
与数值枚举类似,字符串枚举的枚举值都是字符串,但有2点差异:
-
字符串枚举没有自增机制,要求每个成员都显式初始化
-
字符串枚举没有反向映射
对比数值枚举,字符串枚举的一大优势是在运行时仍能保留值的含义(比如Debug时取枚举值,仍然是可读的):
String enums allow you to give a meaningful and readable value when your code runs, independent of the name of the enum member itself.
自增而来的失去了可读性,所以不支持自增。同理,字符串枚举值本就可读,不再需要反向映射:
var Direction; (function (Direction) { Direction["Up"] = "UP"; Direction["Down"] = "DOWN"; Direction["Left"] = "LEFT"; Direction["Right"] = "RIGHT"; })(Direction || (Direction = {}));
四.异构枚举
enum mixEnum { S = 'S', A = 0, B, C = "C", }
枚举值中既有数值也有字符串时,称之为异构枚举(heterogeneous enumeration)。此时根据值的类型,按照数值枚举和字符串枚举区别对待,例如:
var mixEnum; (function (mixEnum) { mixEnum["S"] = "S"; mixEnum[mixEnum["A"] = 0] = "A"; mixEnum[mixEnum["B"] = 1] = "B"; mixEnum["C"] = "C"; })(mixEnum || (mixEnum = {}));
P.S.语法上允许存在这样的“混合”枚举,但几乎没有理由这样做
常量值与计算值
枚举值要么是常量(constant),要么是计算值(computed)
具体的,常量是指:
-
第一个枚举成员,且没有初始值,就隐式赋值为0
-
没有初始值,且上一个枚举成员是个数值常量,就隐式赋值为上一个枚举值加一
-
枚举成员被显式赋值为常量枚举表达式(TypeScript表达式的子集,能在编译时求值,具体见 constant enum expression )
例如:
enum FileAccess { // constant members None, Read = 1 << 1, Write = 1 << 2, ReadWrite = Read | Write, // computed member G = "123".length }
五.联合枚举
特殊的,常量枚举成员中有一部分不需要在编译时求值:字面量枚举成员。包括那些没有初始值的常量枚举成员,或者被初始化成:
-
字符串字面量
-
数值字面量
-
带负号的数值字面量
如果所有成员都是字面量枚举成员,就叫联合枚举(union enums),此时会解锁一些新的特性:
-
枚举本身有了确切的类型含义(是所有枚举成员的联合体)
-
枚举成员也有了类型含义
枚举的类型
把枚举用作类型,可以约束取值集合,进而暴露类似的潜在问题:
// 联合枚举 enum E { Foo, Bar, } // 枚举的类型含义 function f(x: E) { // This condition will always return 'true' since the types 'E.Foo' and 'E.Bar' have no overlap. if (x !== E.Foo || x !== E.Bar) { //... } }
枚举成员的类型
把枚举成员用作类型,可以明确要求只接受该枚举值:
// 联合枚举 enum ShapeKind { Circle, Square, } interface Circle { // 枚举成员的类型含义 kind: ShapeKind.Circle; radius: number; } interface Square { kind: ShapeKind.Square; sideLength: number; } let c: Circle = { // 报错 Type 'ShapeKind.Square' is not assignable to type 'ShapeKind.Circle'. kind: ShapeKind.Square, radius: 100, }
六.常量枚举
上面介绍的几种枚举都与Class类似,具有值和类型的双重含义,因此在运行时也存在(不像接口只存在于编译时),例如:
// 编译前 enum Enum { A = 1, B = A * 2 } let A = Enum.A; // 编译后 var Enum; (function (Enum) { Enum[Enum["A"] = 1] = "A"; Enum[Enum["B"] = 2] = "B"; })(Enum || (Enum = {})); var A = Enum.A;
而 常量枚举仅存在于编译时 ,具体的,删掉枚举声明,引用处编译替换成常量,例如:
// 编译前(注意 const 修饰符) const enum Enum { A = 1, B = A * 2 } let A = Enum.A; // 编译后(Enum完全消失了) var A = 1 /* A */;
因此常量枚举中不允许存在计算值:
const enum Enum { // 报错 const enum member initializers can only contain literal values and other computed enum values. A = Math.PI }
七.环境枚举
仅用作类型约束(或者说只声明不实现)的枚举,这一点与常量枚举类似,但环境枚举(ambient enums)用来描述现有枚举的类型,例如:
declare enum CSSNumericBaseType { 'length', 'angle', 'time', 'frequency', 'resolution', 'flex', 'percent', }
(摘自 DefinitelyTyped/types/w3c-css-typed-object-model-level-1/index.d.ts )
环境枚举与其它枚举的区别在于,环境枚举中没有初始值的枚举成员都当做计算值,不论上一个枚举成员是不是数值常量
参考资料
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- 《Effective Java》学习笔记五——枚举和注解
- c# – 枚举时项目发生变化时是否会影响枚举?
- 测者的测试技术手册:Junit单元测试遇见的一个枚举类型的坑(枚举类型详解)
- 测者的JUnit单元测试探坑记:Junit单元测试遇见的一个枚举类型的坑(枚举类型详解)
- c# – 循环枚举类型
- Python 的枚举类型
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
剑指Offer:名企面试官精讲典型编程题(第2版)
何海涛 / 电子工业出版社 / 2017-5 / 65.00
《剑指Offer:名企面试官精讲典型编程题(第2版)》剖析了80个典型的编程面试题,系统整理基础知识、代码质量、解题思路、优化效率和综合能力这5个面试要点。《剑指Offer:名企面试官精讲典型编程题(第2版)》共分7章,主要包括面试的流程,讨论面试每一环节需要注意的问题;面试需要的基础知识,从编程语言、数据结构及算法三方面总结程序员面试知识点;高质量的代码,讨论影响代码质量的3个要素(规范性、完整......一起来看看 《剑指Offer:名企面试官精讲典型编程题(第2版)》 这本书的介绍吧!