1 定义

枚举 ( Enum ) 类型常用于限定取值在一定范围的场景,类似于 type 关键字约束基础字面量类型值的范围(详见)。
举例:一周的值被限定为七天

  1. // 注意声明方式
  2. enum Week {Sun, Mon, Tue, Wed, Thu, Fri, Sat};
  3. console.log('enum Week =>', Week);

2 理解

2.1 原理

上述例子编译后结果为:

  1. // 注意声明方式
  2. var Week;
  3. (function (Week) {
  4. Week[Week["Sun"] = 0] = "Sun";
  5. Week[Week["Mon"] = 1] = "Mon";
  6. Week[Week["Tue"] = 2] = "Tue";
  7. Week[Week["Wed"] = 3] = "Wed";
  8. Week[Week["Thu"] = 4] = "Thu";
  9. Week[Week["Fri"] = 5] = "Fri";
  10. Week[Week["Sat"] = 6] = "Sat";
  11. })(Week || (Week = {}));
  12. ;
  13. console.log('enum Week =>', Week);

即:枚举成员会以枚举值(默认从 0 开始,顺序递增 1)和枚举名互为键值赋值给枚举对象
最终

  1. console.log('enum Week =>', Week);
  2. enum Week => {
  3. '0': 'Sun',
  4. '1': 'Mon',
  5. '2': 'Tue',
  6. '3': 'Wed',
  7. '4': 'Thu',
  8. '5': 'Fri',
  9. '6': 'Sat',
  10. Sun: 0,
  11. Mon: 1,
  12. Tue: 2,
  13. Wed: 3,
  14. Thu: 4,
  15. Fri: 5,
  16. Sat: 6
  17. }

2.2 枚举值手动赋值

可以对枚举值进行手动赋予初始值,如:

  1. // 注意声明方式
  2. enum Week {Sun = 7, Mon = 1, Tue, Wed, Thu, Fri, Sat};
  3. console.log('enum Week =>', Week);

未赋予初始值的会接着前一个枚举值顺序递增 1 ,如上述编译后:

  1. // 注意声明方式
  2. var Week;
  3. (function (Week) {
  4. Week[Week["Sun"] = 7] = "Sun";
  5. Week[Week["Mon"] = 1] = "Mon";
  6. Week[Week["Tue"] = 2] = "Tue";
  7. Week[Week["Wed"] = 3] = "Wed";
  8. Week[Week["Thu"] = 4] = "Thu";
  9. Week[Week["Fri"] = 5] = "Fri";
  10. Week[Week["Sat"] = 6] = "Sat";
  11. })(Week || (Week = {}));
  12. ;
  13. console.log('enum Week =>', Week);

❗注意:如果手动赋予初始值与顺序递增值重复,会产生值被覆盖的情况

  1. enum Week {Sun = 3, Mon = 1, Tue, Wed, Thu, Fri, Sat};
  2. console.log('enum Week =>', Week);

编译结果

  1. // 注意声明方式
  2. var Week;
  3. (function (Week) {
  4. Week[Week["Sun"] = 3] = "Sun";
  5. Week[Week["Mon"] = 1] = "Mon";
  6. Week[Week["Tue"] = 2] = "Tue";
  7. Week[Week["Wed"] = 3] = "Wed";
  8. Week[Week["Thu"] = 4] = "Thu";
  9. Week[Week["Fri"] = 5] = "Fri";
  10. Week[Week["Sat"] = 6] = "Sat";
  11. })(Week || (Week = {}));
  12. ;
  13. console.log('enum Week =>', Week);

最终打印后发现:Week[3] = "Sun"Week[3] = "Wed" 覆盖。

  1. console.log('enum Week =>', Week);
  2. enum Week => {
  3. '1': 'Mon',
  4. '2': 'Tue',
  5. '3': 'Wed', // 这里被覆盖了
  6. '4': 'Thu',
  7. '5': 'Fri',
  8. '6': 'Sat',
  9. Sun: 3,
  10. Mon: 1,
  11. Tue: 2,
  12. Wed: 3,
  13. Thu: 4,
  14. Fri: 5,
  15. Sat: 6
  16. }

手动赋值的其他情况:

  • 手动赋予初始值可以为负数和小数,后续未赋值的仍会以顺序递增 1
  • 手动赋予初始值可以为字符串,但后续不能含有未赋值的枚举值

    1. // ERROR: Week.eight 枚举成员必须具有初始化表达式。
    2. enum Week {Sun = 7, Mon = 1, Tue, Wed, Thu, Fri, Sat = 'sex', eight, };
    3. console.log('enum Week =>', Week);
    1. // 注意声明方式
    2. enum Week {Sun = 7, Mon = 1, Tue, Wed, Thu, Fri, Sat = 'sex', eight = 'eight'};
    3. console.log('enum Week =>', Week);

    编译后

    1. var Week;
    2. (function (Week) {
    3. Week[Week["Sun"] = 7] = "Sun";
    4. Week[Week["Mon"] = 1] = "Mon";
    5. Week[Week["Tue"] = 2] = "Tue";
    6. Week[Week["Wed"] = 3] = "Wed";
    7. Week[Week["Thu"] = 4] = "Thu";
    8. Week[Week["Fri"] = 5] = "Fri";
    9. Week["Sat"] = "sex";
    10. Week["eight"] = "eight";
    11. })(Week || (Week = {}));
    12. ;
    13. console.log('enum Week =>', Week);

    3 常数项与计算所得项

    枚举值有两种类型:常数项 ( constant member ) 和计算所得项 ( computed member ) ;
    一般情况下都是常数项居多,符合常数项的要求有:

  • 枚举值为数值,未被初始化的可通过前一项顺序递增(第一项默认为 0);

  • 枚举值为带括号的常数表达式;
  • 枚举值为 +, -, ~ 一元运算符的常数表达式或 +, -, *, /, %, &, |, <<, >> 等二元运算符的常数表达式;

其他情况为计算所得项,如前面的字符串值,或其他表达式。

  1. // Sat 与 eight 为 计算所得项
  2. enum Week {Sun = 7, Mon = 1, Tue, Wed, Thu, Fri, Sat = 'sex', eight = 'eight'.length};
  3. console.log('enum Week =>', Week);

与字符串值一样,计算所得项后续不能含有未赋值的枚举值。

4 常数枚举与外部枚举

  • 常数枚举是使用 const enum 定义的枚举,它与普通枚举的区别是:它会在编译阶段被删除,且不能包括计算所得项;

    1. // ERROR: 'eight'.length 含字符串值成员的枚举中不允许使用计算值。
    2. const enum Week {Sun = 7, Mon = 1, Tue, Wed, Thu, Fri, Sat = 'sex', eight = 'eight'.length};
    3. console.log('enum Week =>', Week);
    1. // 常数枚举,编译后被删除
    2. const enum Week {Sun = 7, Mon = 1, Tue, Wed, Thu, Fri, Sat};
    3. const weekend = [Week.Sat, Week.Sun];
    4. console.log('weekend => ', weekend);

    编译后

    ;
    var weekend = [6 /* Sat */, 7 /* Sun */];
    console.log('weekend => ', weekend);
    
  • 外部枚举是使用 declare enum 声明的枚举,前面知道 declare 声明的仅能用于编译时类型检查,编译后会被删除,外部枚举同声明语句一样,常用于声明文件 .d.ts 中;

    // 外部枚举,与常数枚举不同它能使用计算所得项
    declare enum Week {Sun = 7, Mon = 1, Tue, Wed, Thu, Fri, Sat, eight = "eight"};
    const weekend = [Week.Sat, Week.Sun];
    console.log('weekend => ', weekend);
    

    编译后

    ;
    var weekend = [Week.Sat, Week.Sun]; // ReferenceError: Week is not defined
    console.log('weekend => ', weekend);
    
  • 也能同时使用常数枚举和外部枚举,如 declare const ... ,编译结果与常数枚举 const 一样;