枚举

普通枚举

枚举和对象的重要差异在于,对象是单向映射的,我们只能从键映射到键值。而枚举是双向映射的,即你可以从枚举成员映射到枚举值,也可以从枚举值映射到枚举成员。

enum Items {
  Foo,
  Bar,
  Baz
}

const fooValue = Items.Foo; // 0
const fooKey = Items[0]; // "Foo"

这一现象产生的原因与 enum 的编译产物有关,如以上的枚举会被编译为以下 JavaScript 代码。

'use strict';
let Items;
(function (Items) {
  Items[Items['Foo'] = 0] = 'Foo';
  Items[Items['Bar'] = 1] = 'Bar';
  Items[Items['Baz'] = 2] = 'Baz';
})(Items || (Items = {}));

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

常量枚举

常量枚举和枚举相似,只是其声明多了一个 const

const enum Items {
  Foo,
  Bar,
  Baz
}

const fooValue = Items.Foo; // 0

常量枚举和普通枚举的差异主要在可访问性编译产物。对于常量枚举,你只能通过枚举成员访问枚举值(而不能通过值访问成员)。同时,在编译产物中并不会存在一个额外的辅助对象(如上面的 Items 对象),对枚举成员的访问会被直接内联替换为枚举的值。以上的代码会被编译为如下形式。

const fooValue = 0 /* Foo */; // 0