最规范的做法是用 Object.freeze() 冻结的对象常量配合模块化导出,按功能拆分配置文件并统一合并冻结,再结合 TypeScript 定义 readonly 接口以保障类型安全与运行时不可变性。

在 JavaScript 中,全局配置项不应随意散落在代码各处,而应集中定义、明确作用域、防止意外修改。最规范的做法是用 冻结的对象常量(Object.freeze())配合模块化导出,实现真正意义上的“只读常量集”。
用 Object.freeze() 创建不可变配置对象
直接声明普通对象无法阻止属性被修改。必须显式冻结,才能确保运行时不会被误改:
- 定义一个纯对象,包含所有配置项(如 API 地址、超时时间、默认语言等)
- 立即用
Object.freeze()封装,禁用增删改操作 - 冻结后尝试赋值或添加属性会静默失败(严格模式下抛错)
const CONFIG = Object.freeze({
API_BASE_URL: 'https://www.php.cn/link/710ba53b0d353329706ee1bedf4b9b39',
TIMEOUT_MS: 10000,
DEFAULT_LOCALE: 'zh-CN',
IS_PRODUCTION: process.env.NODE_ENV === 'production'
});按模块/功能拆分配置,再统一合并导出
大型项目中配置项较多,建议按语义分组管理,避免单个巨无霸对象:
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
- 分别创建
apiConfig.js、uiConfig.js、featureFlags.js等文件 - 每个文件内部使用
Object.freeze()封装自身配置 - 在主配置文件(如
config/index.js)中组合并再次冻结
// config/api.js
export const API_CONFIG = Object.freeze({ /* ... */ });
<p>// config/ui.js
export const UI_CONFIG = Object.freeze({ /<em> ... </em>/ });</p><p>// config/index.js
import { API_CONFIG } from './api';
import { UI_CONFIG } from './ui';</p><p>export const CONFIG = Object.freeze({
API: API_CONFIG,
UI: UI_CONFIG
});配合 TypeScript 提升类型安全与开发体验
纯 JS 冻结对象只能防运行时修改,但无法约束键名和类型。加上 TypeScript 后可做到:
立即学习“Java免费学习笔记(深入)”;
- 定义
readonly接口或类型,让 IDE 自动提示可用字段 - 导出时用
as const推断字面量类型(适用于简单扁平配置) - 编译期检查非法访问,比如
CONFIG.API_BASE_URLX直接报错
interface AppConfig {
readonly API_BASE_URL: string;
readonly TIMEOUT_MS: number;
readonly DEFAULT_LOCALE: 'zh-CN' | 'en-US';
}
<p>export const CONFIG = Object.freeze<AppConfig>({
API_BASE_URL: '<a href="https://www.php.cn/link/710ba53b0d353329706ee1bedf4b9b39">https://www.php.cn/link/710ba53b0d353329706ee1bedf4b9b39</a>',
TIMEOUT_MS: 10000,
DEFAULT_LOCALE: 'zh-CN'
});避免常见误区
以下做法看似“常量化”,实则不安全或不规范:
- 仅用
const声明对象 → 对象属性仍可修改 - 用
Object.defineProperty手动设writable: false→ 只禁写,不防删/增,且嵌套对象未处理 - 把配置挂到
window.CONFIG上 → 全局污染,易被覆盖,不适用于模块化环境 - 用
class封装配置 → 过度设计,增加实例开销,且难以冻结所有属性

















