跳到主要内容

枚举

枚举是组织收集有关联变量的一种方式。

数字枚举

值为数字的枚举是双向映射的,可以从枚举成员映射到枚举值,也可以从枚举值映射到枚举成员。

enum Direction {
NORTH,
SOUTH,
EAST,
WEST
}

let northValue = Direction.NORTH;
console.log(northValue); // 0

let eastKey: string = Direction[2];
console.log(eastKey); // EAST

被编译成 js 后的代码:

var Direction;
(function (Direction) {
Direction[(Direction['NORTH'] = 0)] = 'NORTH';
Direction[(Direction['SOUTH'] = 1)] = 'SOUTH';
Direction[(Direction['EAST'] = 2)] = 'EAST';
Direction[(Direction['WEST'] = 3)] = 'WEST';
})(Direction || (Direction = {}));
var northValue = Direction.NORTH;
console.log(northValue); // 0
var eastKey = Direction[2];
console.log(eastKey); // EAST

分析高亮行代码,Direction["NORTH"] = 0 是将Direction对象中的NORTH属性值设为 0,接着执行 Direction[0] = "NORTH"

提示

js 赋值运算符返回的是被赋予的值。obj[k] = v 的返回值是 v,因此这里的 obj[obj[k] = v] = k 本质上就是进行了 obj[k] = vobj[v] = k 这样两次赋值。

let obj = {};
let a = (obj['k'] = 1);
console.log(a); // 1
console.log((obj['foo'] = 1)); // 1

数字枚举默认第一个值是从 0 开始,后续依次递增 1,但是也可以改变任意枚举成员关联的数字。

enum Direction {
NORTH, // 0
SOUTH = 3, // 3
EAST, // 4
WEST // 5
}

字符串枚举

枚举类型的值可以是字符串。字符串枚举成员只会进行单次映射。

enum Direction {
NORTH,
SOUTH = 'south',
EAST = 'east',
WEST = 'west'
}

console.log(Direction.NORTH); // "north"

编译成 js 后:

var Direction;
(function (Direction) {
Direction[(Direction['NORTH'] = 0)] = 'NORTH';
Direction['SOUTH'] = 'south';
Direction['EAST'] = 'east';
Direction['WEST'] = 'west';
})(Direction || (Direction = {}));
console.log(Direction.SOUTH); // "south"

如果前面的枚举成员是字符串,那么后面的枚举成员需要赋值。下面的枚举成员 EAST 没有赋值,会报错。

enum Direction {
NORTH,
SOUTH = 'south',
EAST,
WEST = 'west'
}

常量枚举

常量枚举的声明多了一个 const

  • 只能通过枚举成员访问枚举值,而不能通过值访问成员
  • 在编译产物中不会存在一个额外的辅助对象(如下面的 Dir 对象)
  • 访问枚举成员会替换为枚举的值
const enum Dir {
Foo,
Bar,
Baz
}
const r = Dir.Foo;

// 编译后的js
var r = 0; /* Dir.Foo */

如果使用普通枚举,编译后的产物复杂很多:

var Dir;
(function (Dir) {
Dir[(Dir['Foo'] = 0)] = 'Foo';
Dir[(Dir['Bar'] = 1)] = 'Bar';
Dir[(Dir['Baz'] = 2)] = 'Baz';
})(Dir || (Dir = {}));
var r = Dir.Foo;

枚举的静态方法

使用namespace可以给枚举类型添加静态方法。

例子表示是否上班,注意export不可少

enum Weekday {
Monday,
Tuesday,
Wednesday,
Thursday,
Friday,
Saturday,
Sunday
}

namespace Weekday {
export function isBusinessDay(day: Weekday) {
switch (day) {
case Weekday.Saturday:
case Weekday.Sunday:
return false;
default:
return true;
}
}
}

const mon = Weekday.Monday;
const sun = Weekday.Sunday;

console.log(Weekday.isBusinessDay(mon)); // true
console.log(Weekday.isBusinessDay(sun)); // false

开放式枚举

可以拆分枚举块。在延续块中必须设置初始值,否则报错

enum Color {
Red,
Green,
Blue
}

enum Color {
DarkRed = 3,
DarkGreen,
DarkBlue
}

编译后

(function (Color) {
Color[(Color['Red'] = 0)] = 'Red';
Color[(Color['Green'] = 1)] = 'Green';
Color[(Color['Blue'] = 2)] = 'Blue';
})(Color || (Color = {}));
(function (Color) {
Color[(Color['DarkRed'] = 3)] = 'DarkRed';
Color[(Color['DarkGreen'] = 4)] = 'DarkGreen';
Color[(Color['DarkBlue'] = 5)] = 'DarkBlue';
})(Color || (Color = {}));