推荐采用“const + Object.freeze() + 显式挂载”方案:用const声明配置对象,Object.freeze()冻结其属性,浏览器中通过Object.defineProperty挂载到window并设writable=false;避免直接赋值window或仅用const不冻结。

在 JavaScript 中定义一个全局配置常量对象,核心目标是:**可全局访问、不可意外修改、结构清晰、便于维护**。直接用 var 或隐式挂载到 window 上虽然能“访问”,但不防改、不安全、不规范。推荐采用“const + Object.freeze() + 显式挂载”组合方案。
用 const 声明并冻结配置对象
这是最符合现代 JS 语义的做法:先在模块顶层用 const 定义配置对象,再用 Object.freeze() 深层冻结(浅冻结即可满足常量需求),最后选择性挂载到 window(仅限浏览器环境)或导出供其他模块使用。
示例:
const APP_CONFIG = Object.freeze({
API_BASE_URL: 'https://api.example.com/v1',
TIMEOUT: 10000,
ENABLE_DEBUG: false,
SUPPORTED_LANGS: ['zh-CN', 'en-US']
});
// 浏览器中如需全局访问,显式挂载(只读)
if (typeof window !== 'undefined') {
Object.defineProperty(window, 'APP_CONFIG', {
value: APP_CONFIG,
writable: false,
configurable: false,
enumerable: true
});
}
这样定义后:
– APP_CONFIG 在当前模块内不可重新赋值(const 保障);
– 其属性值不可修改、不可新增/删除(Object.freeze() 保障);
– 挂载到 window 后,全局脚本可通过 window.APP_CONFIG 或直接 APP_CONFIG 访问(因它已是全局作用域变量);
– 不会污染 window 的可枚举属性列表(enumerable: true 可按需设为 false)。
避免常见陷阱
以下方式看似简单,实则存在隐患,应避开:
-
直接
window.APP_CONFIG = {...}:该属性默认writable: true,别人仍可window.APP_CONFIG = null覆盖整个对象; -
只用
const但不freeze:对象本身不能重赋值,但内部属性仍可修改,比如APP_CONFIG.TIMEOUT = 30000会成功; -
用全大写命名但无技术约束(如
var APP_CONFIG = {...}):纯靠约定,无任何运行时保护,严格模式下也不报错; -
在函数内隐式创建全局变量(如漏写
var/let/const直接赋值):不仅不安全,还会在严格模式下直接报错。
Vue 或模块化项目中的替代方案
若项目基于 Vue 或使用 ES 模块(import/export),更推荐解耦全局依赖:
- 将配置对象定义在单独文件(如
config.js)中,用export default Object.freeze({...})导出; - 各组件通过
import APP_CONFIG from '@/config'引入——天然模块作用域,无需挂载window,且 Tree-shaking 友好; - 如需在模板中使用,可在
main.js中通过app.config.globalProperties.$config = APP_CONFIG挂载,后续组件中用this.$config访问(注意:仅适用于 Vue 3 的createApp方式)。
需要深冻结?谨慎评估
Object.freeze() 只冻结对象第一层属性。如果配置里有嵌套对象(如 { auth: { tokenExpire: 3600 } }),其子对象仍可被修改。此时可考虑:
- 保持配置扁平化(推荐):避免深层嵌套,提升可读与可控性;
- 手动冻结嵌套对象:
Object.freeze({ auth: Object.freeze({ tokenExpire: 3600 }) }); - 使用第三方库如
deep-freeze(仅开发/测试阶段有用,生产环境一般不必要)。











