枚举类型
枚举类型在很多语言中都有,一般用于一组命名的场数,当一个变量会出现几种可能的取值是,可以用到枚举类型;
数字枚举
当我们声明一个枚举时,虽然看上去好像煤油给它赋值,但是他们的值其实就是默认的数字类型,并且默认从0开始依次累加:
enum Direction {
Up,
Down,
Left,
Right
}
console.log(Direction.Up === 0); // true
console.log(Direction.Down === 1); // true
console.log(Direction.Left === 2); // true
console.log(Direction.Right === 3); // true
因此当我们把第一个值赋值后,后边就会参照第一个值进行累加操作,比如:
/**
* @description 初始赋值的枚举
*/
enum Direct {
Up = 10,
Down,
Left,
Right
}
console.log(Direct.Down); // 11
console.log(Direct.Left); //12
console.log(Direct.Right); //13
原理明白了,我们看一下实际编译后,这段ts代码变成怎么想的js代码;
/**
* @description 初始赋值的枚举
*/
var Direct;
(function (Direct) {
Direct[Direct["Up"] = 10] = "Up";
Direct[Direct["Down"] = 11] = "Down";
Direct[Direct["Left"] = 12] = "Left";
Direct[Direct["Right"] = 13] = "Right";
})(Direct || (Direct = {}));
console.log(Direct.Down); //11
console.log(Direct.Left); //12
console.log(Direct.Right); //13
字符串枚举
枚举类型可以是数字当然也可以是字符串,下边我们看一下字符串枚举类型:
/**
* @description 字符串枚举
*/
enum DirectStr {
Up = 'up',
Down = 'down',
Left = 'left',
Right = 'right'
}
console.log(DirectStr['Up'], DirectStr.Right) // up, right
异构枚举
这种结构是什么意思呢?就是既有字符串枚举又由数字枚举,是不是能混合使用呢?试一下吧;
/**
* @description 异构枚举
*/
enum StrAndNumberEnum {
no = 0,
yes = 'ok'
}
console.log(StrAndNumberEnum.no, StrAndNumberEnum.yes) // 0,yes
运行发现,这样是没有问题的,一般情况我们不会使用这种枚举,但是从技术角度,是可行的;
反向映射
我们想一下既然枚举类型可以正常获取值;但是我们想一下能不通过反向映射获取到对应的键呢?可以试一下。
/**
* @description 反向映射
*/
enum Reverse {
Up = 10,
Down,
Left,
Right
}
console.log(Reverse[11]) //Down
console.log(Reverse[12]) //Left
console.log(Reverse[13]) //Right
这是不是很奇怪,为啥子?我们都知道js的对象一般都是键值对的正向映射,即 name -> value,为什么正在枚举正反相同时映射?我们需要了解和思考一下枚举的本质;
枚举的本质
以上边Reverse 枚举类型为例子,我们看一下枚举没醒被编译后会变成什么样
/**
* @description 反向映射
*/
var Reverse;
(function (Reverse) {
Reverse[Reverse["Up"] = 10] = "Up";
Reverse[Reverse["Down"] = 11] = "Down";
Reverse[Reverse["Left"] = 12] = "Left";
Reverse[Reverse["Right"] = 13] = "Right";
})(Reverse || (Reverse = {}));
console.log(Reverse[11]); //
console.log(Reverse[12]);
console.log(Reverse[13]);
通过分析代码,我们发现Reverse是通过一个自执行函数,通过参数透传的方式为自定义函数赋值;其中Reverse[Reverse[“Up”]=10] = Up我们可以把它理解成Reverse[10]= “Up”;这个特殊的构造,导致其拥有正反向同时映射的特性;
联合枚举及枚举成员的类型
枚举中的所有成员都是字面量类型的值,这种请况,每个枚举成员和枚举值本身都可以作为类型来使用;
- 任何字符串字面量:
/**
* @description 任何字符串字面量
*/
const enum EveryStr {
One = '1',
Two = '2',
Three = '3',
Four = '4'
}
- 任何数字字面量:
/**
* @description 任何数字字面量
*/
const enum EveryNum{
Up,
Down,
Left,
Right
}
枚举成员的类型
每个枚举的成员拥有字面量枚举时,被赋予了一定特殊的语义,发现枚举成员成了类型。
比如我们声明一个数字类型:
enum EveryNum{
Up,
Down,
Left,
Right
}
const up = 0;
console.log(up ===EveryNum.Up ); //true
枚举成员作为值来使用,通过代码是ok的,因为EveryNum.Up本身默认值就是0;我们写一个类型来验证一下
type c = 0
declare let b: c
b = 1 // 不能将类型“1”分配给类型“0”
b = Direction.Up
这里b在赋值的时候会发现报错了;这个就是枚举的成员被赋予特殊的类型;类型与类型之间不可以重新赋值;
联合类型
这个比较复杂,这里简单验证一下;
enum KeyHandler {
Up,
Down,
Left,
Right
}
declare let keyTest: KeyHandler;
enum Animal {
Dog,
Cat
}
keyTest = KeyHandler.Up;
keyTest = Animal.Dog // 不能将类型“Animal.Dog”分配给类型“KeyHandler”
发现 把 testKey声明为KeyHandler类型,可以看成我们声明一个联合类型 KeyHandler .Up | KeyHandler .Down| KeyHandler .Left| KeyHandler .Right,只允许这四种类型成员才符合要求。
枚举合并
我们可以把多次声明的枚举进行自动合并;
/**
* @description 枚举自动合并
*/
enum Collection {
Name = "张三",
Sex = 0,
Age = "21",
Address = "四川省成都市高新区"
}
enum Collection {
nation = "汉族"
}
编译成js后,我们看一下是什么样子
var Collection;
(function (Collection) {
Collection["Name"] = "\u5F20\u4E09";
Collection[Collection["Sex"] = 0] = "Sex";
Collection["Age"] = "21";
Collection["Address"] = "\u56DB\u5DDD\u7701\u6210\u90FD\u5E02\u9AD8\u65B0\u533A";
})(Collection || (Collection = {}));
(function (Collection) {
Collection["nation"] = "\u6C49\u65CF";
})(Collection || (Collection = {}));
为枚举增加静态方法
借助于namespace命名空间,我们甚至可以给枚举增加一些静态方法。尝试一下;
enum Month {
January,
February,
March,
April,
May,
June,
July,
August,
September,
October,
November,
December,
}
function isSummer(month: Month) {
switch (month) {
case Month.June:
case Month.July:
case Month.August:
return true;
default:
return false
}
}
借助命名空间把枚举和静态方法结合起来;
namespace Month {
export function isSummer(month: Month) {
switch (month) {
case Month.June:
case Month.July:
case Month.August:
return true;
default:
return false
}
}
}
console.log(Month.isSummer(Month.June)) //true
console.log(Month.isSummer(Month.January)) // false
总结
本次笔记重点探讨了一下枚举的一些形式和特性;欢迎交流