使用 Object.freeze() 的 JavaScript 常量

2025-06-04

使用 Object.freeze() 的 JavaScript 常量

这是一个非常简单的观察,我之所以想写出来,是因为我几乎从未见过这种技术被广泛使用。几乎每个程序员都熟悉“常量”的概念。我指的不仅仅是constJavaScript 中的关键字。我指的是一个通用的概念,即一个变量只被设置一次——而且只能设置一次——因为一旦设置,该变量的值就不应该改变。换句话说,它的值应该保持不变

使用现代 JavaScript 实现此目的的最常见方式如下:



const SALES_TAX_ALABAMA = 0.04;
const SALES_TAX_FLORIDA = 0.06;
const SALES_TAX_LOUISIANA = 0.0445;


Enter fullscreen mode Exit fullscreen mode

一旦使用这些关键字实例化这些变量const,任何重新赋值的尝试都会导致运行时错误。这种方法……“有效”,但可能有点笨重。在每个想要利用这些变量的脚本中,你都需要预先定义它们。如果这些变量在整个代码库中都使用,这种方法会很不方便。

使用现代 JavaScript,另一种方法是将export这些值放在一个文件中。这种方法如下所示:



// constants.js
export const SALES_TAX_ALABAMA = 0.04;
export const SALES_TAX_FLORIDA = 0.06;
export const SALES_TAX_LOUISIANA = 0.0445;


Enter fullscreen mode Exit fullscreen mode

这使得我们的常量在整个应用中通用且更易于访问。但我认为这仍然有些笨重。因为每次我们想在另一个文件中使用这些变量中的任何一个时,每个变量都必须用import.开头的 ...

我还觉得这种方法很笨重,因为它与我们 IDE 的自动完成功能不太兼容。你写代码的时候,有多少次意识到需要用到像上面那样的常量?但你却想不起来这些变量的具体名称于是你开始输入:ALA ...,希望看到阿拉巴马州销售税率常量弹出来。

但是你的 IDE 没有提供自动补全/导入该值的功能,因为没有以 "ALA" 开头的常量。所以,在你又尝试了几次凭记忆输入名称来获取该值之后,你最终放弃了,打开文件,constants.js亲自通读整个文件,看看这些变量到底是怎么命名的。


图片描述

物体来救援(???)

这就是我喜欢使用 JavaScript对象来创建命名空间约定的原因。(事实上,我写了一整篇文章来介绍它。你可以在这里阅读:https://dev.to/bytebodger/why-do-js-devs-hate-namespaces-2eg1

当你将值保存为对象中的键/值对时,你的 IDE 会变得更加强大。只要你输入对象的初始名称,然后输入.几乎任何现代 IDE 都会自动提取该对象中存在的所有潜在键。

这意味着您可以重构常量文件,使其看起来像这样:



// constants.js
export const CONSTANT = {
  SALES_TAX: {
    ALABAMA = 0.04;
    FLORIDA = 0.06;
    LOUISIANA = 0.0445;  
  },
};


Enter fullscreen mode Exit fullscreen mode

这增强了 IDE 的自动完成功能。但是……它也有一个缺点。因为在 JavaScript 中,用该关键字定义的对象实际上const并不是一个“常量”。

通过上面的例子,下面的代码将抛出一个急需的运行时错误:



import { CONSTANT } from './constants';

CONSTANT = 'Foo!';


Enter fullscreen mode Exit fullscreen mode

CONSTANT由于使用了关键字定义,因此会抛出运行时错误const,并且一旦设置就无法重新赋值。然而……这并不一定能保护对象的嵌套内容不被重新赋值。

因此以下代码不会引发运行时错误:



import { CONSTANT } from './constants';

CONSTANT.SALES_TAX.ALABAMA = 0.08;


Enter fullscreen mode Exit fullscreen mode

这真的没什么用,不是吗?毕竟,如果任何程序员,在代码库的任何其他部分工作,都可以随意重新分配一个“常量”的值,那么它根本就不是一个常量。


图片描述

Object.freeze()前来救援(!!!)

这就是我Object.freeze()在所有常量上都使用它的原因。(而且这是一种简单的技术,除了我自己的代码外,我很少见到。)

修改后的代码如下所示:



// constants.js
export const CONSTANT = Object.freeze({
  SALES_TAX: Object.freeze({
    ALABAMA = 0.04;
    FLORIDA = 0.06;
    LOUISIANA = 0.0445;  
  }),
});


Enter fullscreen mode Exit fullscreen mode

现在,如果我们尝试运行此代码,它将引发运行时错误:



import { CONSTANT } from './constants';

CONSTANT.SALES_TAX.ALABAMA = 0.08;


Enter fullscreen mode Exit fullscreen mode

当然,这有点冗长,因为你需要Object.freeze() 对每个对象都使用,即使是嵌套在另一个对象中的对象。在上面的例子中,如果你不冻结SALES_TAX对象,你仍然可以重新赋值给它。


图片描述

更好的方法

我已经知道有些开发者不喜欢这种方法,因为他们不喜欢在文件的Object.freeze()每个对象constants.js上都使用这种方法。这没关系,因为这里还有空间容纳其他样式。但我坚决推荐这种方法,原因很简单。

单个常量文件

Object.freeze()如果您只想维护单个 文件,则无需使用constants.js。您可以恢复到“传统”的做法,如下所示:



// constants.js
export const SALES_TAX_ALABAMA = 0.04;
export const SALES_TAX_FLORIDA = 0.06;
export const SALES_TAX_LOUISIANA = 0.0445;


Enter fullscreen mode Exit fullscreen mode

但我可以根据几十年的经验告诉你,打开一个定义了数百个constants.js变量的通用文件并不罕见。当这种情况发生时,我经常会发现类似这样的内容:



// constants.js
export const SALES_TAX_ALABAMA = 0.04;
export const SALES_TAX_FLORIDA = 0.06;
export const SALES_TAX_LOUISIANA = 0.0445;
/*
  ...hundreds upon hundreds of other constants 
  defined in this file...
*/
export const ALABAMA_SALES_TAX = 0.04;


Enter fullscreen mode Exit fullscreen mode

你看到发生了什么吗?文件变得如此之大,命名约定又如此随意,以至于某个时候,开发人员在寻找阿拉巴马州的销售税值时,没有找到,然后为相同的值创建了第二个变量,其命名约定完全不同

这就引出了我的第二点:

对象促进分类命名结构

当然,即使使用对象按照分类约定保存这些值,懒惰的开发人员仍然有可能在同一个文件中定义两次阿拉巴马州销售税率的值。但这种情况发生的可能性要小得多。因为,当你仔细查看constants.js文件中现有的值时,更容易发现已经有一个完整的“部分”专门用于销售税率。这意味着未来的开发人员更有可能找到已经存在的值。如果文件中不存在该值,他们更有可能按照正确的分类顺序添加该值。

使用我们 IDE 的自动完成功能搜索这些值时,这也变得更加合乎逻辑。只要您输入CONSTANTS.,IDE 就会显示主对象下的所有“子层” CONSTANTS,并且您会立即发现它已经包含一个专门用于销售税率的部分。

对象允许变量键名

假设您已经有如下代码:



const state = getState(shoppingCartId);


Enter fullscreen mode Exit fullscreen mode

如果常量的命名约定如下所示:



// constants.js
export const SALES_TAX_ALABAMA = 0.04;


Enter fullscreen mode Exit fullscreen mode

那么就没有简单的方法来动态地提取销售税率了state。但是如果你的常量命名约定如下所示:



// constants.js
export const CONSTANT = Object.freeze({
  SALES_TAX: Object.freeze({
    ALABAMA = 0.04;
    FLORIDA = 0.06;
    LOUISIANA = 0.0445;  
  }),
});


Enter fullscreen mode Exit fullscreen mode

然后你可以这样做:



import { CONSTANTS } = './constants';

const state = getState();
const salesTaxRate = CONSTANT.SALES_TAX[state.toUpperCase()];


Enter fullscreen mode Exit fullscreen mode
文章来源:https://dev.to/bytebodger/javascript-constants-with-objectfreeze-4beg
PREV
React 正在自我毁灭
NEXT
如何招聘程序员