JavaScript中确保枚举定义不被更改的方法
技术背景
在JavaScript里,枚举并不是原生支持的数据类型。不过在实际开发时,我们常常需要定义一组固定的常量,也就是枚举,来提升代码的可读性与可维护性。然而,JavaScript是动态语言,怎样保证枚举定义不被更改,成为了一个关键问题。
实现步骤
1. 使用Object.freeze()
方法
自ES5的1.8.5版本起,能够借助Object.freeze()
方法来冻结对象,从而防止对象的属性被修改、添加或者删除。示例如下:
1
| const DaysEnum = Object.freeze({ "monday": 1, "tuesday": 2, "wednesday": 3 });
|
或者:
1 2
| const DaysEnum = { "monday": 1, "tuesday": 2, "wednesday": 3 }; Object.freeze(DaysEnum);
|
2. 运用Proxy
对象
可以通过Proxy
对象模拟传统编程语言中的枚举行为,当尝试访问不存在的枚举项或者添加/更新枚举项时,会抛出错误。示例代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| class Enum { constructor(enumObj) { const handler = { get(target, name) { if (typeof target[name] != 'undefined') { return target[name]; } throw new Error(`No such enumerator: ${name}`); }, set() { throw new Error('Cannot add/update properties on an Enum instance after it is defined'); } }; return new Proxy(enumObj, handler); } }
const roles = new Enum({ ADMIN: 'Admin', USER: 'User', });
|
3. 采用下划线表示法变量
借助下划线表示法变量来定义枚举,能够在代码压缩时减少文件大小,同时提升性能、便于调试和协作。示例如下:
1 2 3 4 5 6 7 8
| const ENUM_COLORENUM_RED = 0; const ENUM_COLORENUM_GREEN = 1; const ENUM_COLORENUM_BLUE = 2; const ENUMLEN_COLORENUM = 3;
if (currentColor === ENUM_COLORENUM_RED) { }
|
核心代码
使用Object.freeze()
1
| const DaysEnum = Object.freeze({ "monday": 1, "tuesday": 2, "wednesday": 3 });
|
使用Proxy
对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| class Enum { constructor(enumObj) { const handler = { get(target, name) { if (typeof target[name] != 'undefined') { return target[name]; } throw new Error(`No such enumerator: ${name}`); }, set() { throw new Error('Cannot add/update properties on an Enum instance after it is defined'); } }; return new Proxy(enumObj, handler); } }
const httpMethods = new Enum({ DELETE: "DELETE", GET: "GET", OPTIONS: "OPTIONS", PATCH: "PATCH", POST: "POST", PUT: "PUT" });
|
下划线表示法变量
1 2 3 4 5 6 7 8
| const ENUM_COLORENUM_RED = 0; const ENUM_COLORENUM_GREEN = 1; const ENUM_COLORENUM_BLUE = 2; const ENUMLEN_COLORENUM = 3;
if (currentColor === ENUM_COLORENUM_RED) { }
|
最佳实践
- 使用
Object.freeze()
:适用于简单的枚举定义,能够快速冻结对象,防止属性被修改。 - 使用
Proxy
对象:适用于需要严格控制枚举访问和修改的场景,当访问不存在的枚举项或者修改枚举项时,会抛出错误。 - 下划线表示法变量:适用于大型项目,在代码压缩时能减少文件大小,提升性能,同时便于调试和协作。
常见问题
1. Object.freeze()
在旧浏览器中不支持
IE8等旧浏览器不支持Object.freeze()
方法。针对这种情况,可以采用字符串常量的方式来定义枚举,示例如下:
1 2 3 4 5 6
| var CONST_WILD_TYPES = { REGULAR: 'REGULAR', EXPANDING: 'EXPANDING', STICKY: 'STICKY', SHIFTING: 'SHIFTING' };
|
2. 枚举值被意外修改
即便使用了Object.freeze()
,也无法阻止将枚举值赋给变量后,变量被重新赋值。若要实现更强的类型安全,可以使用TypeScript或者Flow等工具。