入个TypeScript的门(2)——枚举

161 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第8天,点击查看活动详情

枚举,其实它就是一个对象,只不过我感觉他又有点像Map,就是存的键值对(一一对应那种),但是它又比Map多了一些其他的特性...

枚举的定义与作用

在TS中,枚举的定义就是很简单的,使用一个关键字——enum

enum Days {
    one,
    two,
    three,
    four
}

这样我们定义好了一个枚举了。那么枚举定义好有什么用呢?那就得谈谈枚举的特性了:(我们来获取刚才使用的枚举)

...
let day = Days['one']; 
console.log(day);   //0
let key = Days[0];
console.log(key);   //one

我们发现我们的day居然有一个初始值,为0。这是为啥呢?我们来看一下它编译为JS后的代码:

{
    var Days = void 0;
    (function (Days) {
        Days[Days["one"] = 0] = "one";
        Days[Days["two"] = 1] = "two";
        Days[Days["three"] = 2] = "three";
        Days[Days["four"] = 3] = "four";
    })(Days || (Days = {}));
}

我们发现它还真是一个对象,然后通过给这个对象赋值的形式,让这个对象有一种类似双层映射的感觉。其实它内部就是:

{
  '0': 'one',
  '1': 'two',
  '2': 'three',
  '3': 'four',
  one: 0,
  two: 1,
  three: 2,
  four: 3
}

不过从中我们也看出来了一个特性:那就是枚举默认就将第一个属性赋值为0,然后后面的属性依次在前一个的属性的值的基础上加1。

自定义值

但是枚举除了会自己加值以外,我们也可以自己定义值:

enum Days {
    one=1,
    two,
    three,
    four
}

这时候one=1,two就等于2了,three就等于3,four就等于4。

enum Days {
    one=1,
    two,
    three=6,
    four
}

那么这时候他们又等于多少呢?答案是:

{
  '1': 'one',
  '2': 'two',
  '6': 'three',
  '7': 'four',
  one: 1,
  two: 2,
  three: 6,
  four: 7
}

所以得出结论:只要在定义枚举时,没有给他赋值的,就会以它上一个为基准进行值+1。但是如果定义重了怎么办?那么这时候虽然不会报错,但是会造成双向映射出现问题:

enum Days {
    one=3,
    two=2,
    three,
    four
}
console.log(Days);
---------------------------
{
  '2': 'two',
  '3': 'three',
  '4': 'four',
  one: 3,
  two: 2,
  three: 3,
  four: 4
}

我们发现这时候one虽然指向3,但是3指向的是three了。所以最好不要搞重复了。

枚举的值为字符串

最后,枚举的值不一定是number类型,它也可以是字符串。

  enum Days {
    one='一',
    two,
    three,
    four
}

注意这样是不行的,会报错:Enum member must have initializer.我们如果需要枚举的值不用number类型,那么就必须满足以下几个条件之一:

  • 要么全部给他赋值
  • 要么在不复制的第一个给一个number常量
  • 付其他值的在最后一个
  enum Days {
    one='一',
    two=2,
    three,
    four
}
-------或者----------------
  enum Days {
    one='一',
    two='二',
    three='三',
    four='四'
}
-------或者----------------
  enum Days {
    one,
    two,
    three,
    four='四'
}
-------或者----------------
  enum Days {
    one='一',
    two=2,
    three,
    four
}

但是我们需要注意的是:如果我们赋其他类型的值时,就失去了双向映射了,我们可以来看一下编译后的代码:

    var Days = void 0;
    (function (Days) {
        Days["one"] = "\u4E00";
        Days["two"] = "\u4E8C";
        Days["three"] = "\u4E09";
        Days["four"] = "\u56DB";
    })(Days || (Days = {}));
    console.log(Days);
}
-------------------------
{ one: '一', two: '二', three: '三', four: '四' }

也就是说我们不能通过Days['一']来反向获取值了。双向映射只能在数字枚举中存在。

常量枚举

最后,还有一种枚举叫常量枚举,它和普通枚举的区别在定义上就是多了个const关键字:

const enum Days {
    one='一',
    two='二',
    three='三',
    four='四'
}

但是它是有区别的,因为我们普通定义的枚举,它编译后是存在JS代码的,但是常量枚举编译后是没有JS代码的,它只会将使用这个枚举的地方给替换掉:

  const enum Days {
    one='一',
    two='二',
    three='三',
    four='四'
}
console.log(Days['one'] === '一');
--------------------------------------
console.log("\u4E00" /* Days['one'] */ === '一');

我们可以发现最后就只有一行输出语句,而且把Days['one']给替换为了