背景
我第一次遇到这个问题是在一次面试中,面试官和我聊到枚举,然后他问了我这个问题,当时我有点懵,我也没想过这个问题,可能是我使用枚举的次数太少了。我那时候自认为这个问题应该不是很难,应该只是我理解不到位而已,我往上搜一下,应该就能知道答案了,所以后面我也没有找面试官要这个问题的答案。之后这个问题就一直在我脑海中,我在搜索引擎搜索了相关问题,但是我对答案都不是很满意,没有办法说服自己。随着自己使用 typescript
的深入,自己也慢慢地理解这个问题。所以记录一下这次感悟。
枚举编译之后就是对象
不知道大家有没有留意过枚举,编译过后的样子,一个 DayEnum
编译之后的样子
enum DayEnum {
day = '天',
week = '周',
month = '月',
year = '年'
}
"use strict";
var DayEnum;
(function (DayEnum) {
DayEnum["day"] = "\u5929";
DayEnum["week"] = "\u5468";
DayEnum["month"] = "\u6708";
DayEnum["year"] = "\u5E74";
})(DayEnum || (DayEnum = {}));
这样看起来,和对象好像没有什么区别,如果我们建立一个对象,也能建立 key
对 value
的映射
const DayEnum = {
day: '天',
week: '周',
month: '月',
year: '年'
}
好像枚举和对象没有什么区别,于是我翻了一下 Typescript 中文网 ,看到了 反向映射
,我心想,要是枚举能反向映射的话,这就厉害了,这是 JavaScript
中对象做不到的,于是就想起了以前要做反向映射遍历对象 key
的那种痛苦,觉得有救了。然后看到了一句不怎么起眼但让我绝望的话:
要注意的是 不会为字符串枚举成员生成反向映射。
这……也就是说,我的枚举要对应数字类型才可以,比如
enum DayEnum {
day = 1,
week = 2,
month = 3,
year = 4
}
但是我觉得如果是 1、2、3、4
的话,代码的可读性会差很多吧,一般来说,正常的开发都会尽量去避免这种 “魔法数字”。不过之前的业务中也有遇到过。不过这里有个细节,一定要小心,应该枚举对数字类型生成了反向映射,所以在遍历的时候,会出现下面这种情况:
for (const key in DayEnum) console.log(key)
原来的 value
值也会出现在 key
中,使用反向映射时,遍历枚举类型要注意咯
可以在typescript 的 playground 中尝试一下!
枚举类型不可以被修改
最后让我感觉枚举类型和普通对象的区别的是这么一段代码
// 这段代码是可以正常运行的
const DayEnum = {
day: '天',
week: '周',
month: '月',
year: '年'
}
DayEnum.day = 'day'
enum DayEnum {
day = '天',
week = '周',
month = '月',
year = '年'
}
// 这段代码没法通过编译的
DayEnum.day = 'day'
Cannot assign to ‘day’ because it is a read-only property.
我在想是不是可以这样理解:枚举是一个 只读类型
的对象。
总结
后来我思考了一阵子,我感觉是自己对 TypeScript
的理解还只是 JavaScript
的另一种写法,随便加个类型就行,不行就 any
,没有从 JavaScript
的思维中走出来。从枚举这个问题上来看,如果用对象的话,这就是一个潜在的问题,而且你可能永远都不会发现,但是用 TypeScipt
的话,你可以避免这种问题的发生,他避免得你甚至都毫无察觉。对日常中的代码还是要多一些思考,细心一点,我相信没有学不到东西的岗位,只有不够细心的“打工人”