Enum

Enum 是在 TypeScript 中新增的语法,也叫做枚举,个别用它来治理多个雷同系列的常量(即不能被批改的变量),用于状态的判断。

在 Web 中比拟常见的状态判断,是在解决申请时,要针对不同的响应状态码做对应的解决:

const handleResponseStatus = (status: number): void => {  switch (status) {    case 200: // 申请胜利时      // Do something...      break;    case 400: // 申请失败时      // Do something...      break;    default:      throw (new Error('No have status code!'));  }};

但因为响应状态码都是事后定义好的,所以没什么争议,代码写成这样看也很失常,然而如果后端在服务器产生谬误时自定义了一些编码,并通知前端,这些代码都代表什么谬误,那么下面的函数可能会变成这样:

const handleWrongStatus = (status: string): void => {  switch (status) {    case 'A':      // Do something...      break;    case 'B':      // Do something...      break;    case 'C':      // Do something...      break;    default:      throw (new Error('No have wrong code!'));  }};

如果是这种代码,别说是刚接手的人,就算是你本人两星期前写的,恐怕不去翻文档也想不起它们都代表什么了吧。

然而如果善用 Enum ,就能够防止上述产生的状况。

根本用法

先来看看 Enum 该怎么定义,它和 Object 的用法很像:

enum requestStatusCodes {  error,  success,}

不须要在内容与名称之间加等号,间接在大括号内叙述该 Enum 中具备哪些变量,与其说是变量,不如说是常量更失当些,因为在 Enum 中的值是不可批改的,所以也不用放心这些定义好的规定会在代码执行的过程中产生扭转,导致执行谬误。

而既然 Enum 是用来定义同一个系列常量的,那这些常量应该都能保护特定的值。没错,在 Enum 中的每个常量,都能够通过 = 来指定具体的值 。

但如果是像后面的 requestStatusCodes ,没有为 errorsuccess 指定具体的值也不会出错,因为 TypeScript 会从 0 开始主动递增定义值,所以签名的 requestStatusCodes 会和上面的后果雷同:

enum requestStatusCodes {  error = 0,  success = 1,}console.log(requestStatusCodes.error) // 0console.log(requestStatusCodes.success) // 1

除了数字外,也能够定义为字串:

enum requestWrongCodes {  missingParameter = 'A',  wrongParameter = 'B',  invalidToken = 'C',}console.log(requestWrongCodes.wrongParameter) // 'B'

当然也能够在一个 enum 中设定不同的类型,但这样一点意义都没有:

enum requestStatusCodes {  error = 0,  success = 'OK',}

理解根本的 Enum 怎么定义后,接着就来改写后面代码中的 handleResponseStatushandleWrongStatus ,让它们在语义上可能更明确。

首先用 Enum 定义两者的状态形容:

enum requestStatusCodes {  error = 400,  success = 200,}enum requestWrongCodes {  missingParameter = 'A',  wrongParameterType = 'B',  invalidToken = 'C',}

而后批改 handleResponseStatushandleWrongStatus 中的 Switch 判断:

const handleResponseStatus = (status: number): void => {  switch (status) {    case requestStatusCodes.success:      // Do something...      break;    case requestStatusCodes.error:      // Do something...      break;    default:      throw (new Error('No have status code!'));  }};const handleWrongStatus = (status: string): void => {  // 如果感觉 requestWrongCodes.missingParameter 太长了,也能够用以下形式:  const { missingParameter, wrongParameterType, invalidToken, } = requestWrongCodes;  switch (status) {    case missingParameter:      // Do something...      break;    case wrongParameterType:      // Do something...      break;    case invalidToken:      // Do something...      break;    default:      throw (new Error('No have wrong code!'));  }};

批改后的代码就变得直观多了,因为状态码都被放到了 Enum 中对立治理,所以就能用常量名来代表它们,之后不论过了多久,能够明确的晓得这里再做什么,甚至连注解或文档都不必写了,因为代码就是最好的文档。

善用 Enum 能使代码相对是不可或缺的,但就算没应用 TypeScript 也别灰心,因为 TypeScript 最终会被转换为 JavaScript ,那来看看如何间接用 JavaScript 实现 Enum 吧!

用原生 JavaScript 实现 Enum

在后面说过 Enum 很像 Object ,如果钻研一下 Enum 被编译成 javascript 之后的代码,就会发现还真的是 Object。

Enum 被编译后会变成 Key 和 Value 反向对应的对象,这样看起来非常简单,为了方便使用,上面把它的编译形式写成一个函数:

const newEnum = (descriptions) => {  const result = {};  Object.keys(descriptions).forEach((description) => {    result[result[description] = descriptions[description]] = description;  });  return result;};const responseStatus = newEnum({  error: 400,  success: 200,});// { '200': 'success', '400': 'error', error: 400, success: 200 }console.log(responseStatus);

尽管失去的后果雷同,然而丢失了 Enum 中最可贵的常量特色,如果不能让它变成不可批改,那就有可能会在代码里不经意地改变它,导致执行后果可能出错,于是能够在最初利用 Object.freeze() ,让内部操作无奈新增、删除或从新定义任何 Property :

const newEnum = (descriptions) => {  const result = {};  Object.keys(descriptions).forEach((description) => {    result[result[description] = descriptions[description]] = description;  });  return Object.freeze(result);};const responseStatus = newEnum({  error: 400,  success: 200,});// 即便不小心批改了responseStatus['200'] = 'aaaaaaaa';// 依然是 { '200': 'success', '400': 'error', error: 400, success: 200 }console.log(responseStatus);

这样就能简略在 JavaScript 中实现 Enum 了。

const Enum 的用法

从后面的 JavaScript 代码中能够看到 Enum 编译过后会变成 Key 和 Value 相互对应的 Object ,也就是说不论是用 Key 还是Value 都能够取出对应的值,

然而如果用 const 申明 Enum ,编译之后就不会产生 Object。

间接看例子,假如我把 responseStateconst 从新生命,且也是以 handleResponseStatus 应用该 Enum 做判断:

enum responseStatus {  error = 400,  success = 200,}const handleResponseStatus = (status: number): void => {  switch (status) {    case responseStatus.success:      console.log('申请胜利!');      break;    case responseStatus.error:      console.log('申请失败!');      break;    default:      throw (new Error('No have status code!'));  }};

看起来一切正常,不过在编译后的 JavaScript 中,会发现 Enum 并没有产生 Object ,而是间接用 const 申明在 Enum 中的值。

const 申明 Enum 有几个益处:

  1. 假如要用到的 Enum 十分多,那在执行时就会不停地应用 IIFE 产生 Object 将 Key 和 Value 绑定到 Object,会造成一些效率上的损失,也会减少内存,然而 const 并不会产生 Object ,也就不会有以上的问题。
  2. 就算到的 Enum 不多,判断时也须要始终从 Object 中找出对应的值,而如果是用 const 申明 Enum ,在编译成 JS 时就将申明的值间接放入判断中。

不过这样也就没法从 Enum 中反向取值了,因为它并不会产生对象:

const enum responseStatus {  error = 400,  success = 200,}// 会出错,因为曾经没有对象可供查找了console.log(responseStatus[400])// 但这个不会有问题,因为编译的时候会间接填值console.log(responseStatus.error)// 编译后:// console.log(400)


本文首发微信公众号:前端先锋

欢送扫描二维码关注公众号,每天都给你推送陈腐的前端技术文章


欢送持续浏览本专栏其它高赞文章:

  • 深刻了解Shadow DOM v1
  • 一步步教你用 WebVR 实现虚拟现实游戏
  • 13个帮你进步开发效率的古代CSS框架
  • 疾速上手BootstrapVue
  • JavaScript引擎是如何工作的?从调用栈到Promise你须要晓得的所有
  • WebSocket实战:在 Node 和 React 之间进行实时通信
  • 对于 Git 的 20 个面试题
  • 深刻解析 Node.js 的 console.log
  • Node.js 到底是什么?
  • 30分钟用Node.js构建一个API服务器
  • Javascript的对象拷贝
  • 程序员30岁前月薪达不到30K,该何去何从
  • 14个最好的 JavaScript 数据可视化库
  • 8 个给前端的顶级 VS Code 扩大插件
  • Node.js 多线程齐全指南
  • 把HTML转成PDF的4个计划及实现

  • 更多文章...