object.defineproperty(globalthis, 'config', { value: config, writable: false, configurable: false }) 可锁死全局变量绑定,因 writable: false 阻止重赋值、configurable: false 禁止删除或重定义,再配合 object.freeze(config) 冻结内部属性,实现内外双重防护。

为什么直接赋值的全局配置会被意外修改
全局配置对象(比如 window.CONFIG 或 globalThis.APP_CONFIG)一旦用普通赋值方式声明,就没有任何防护能力。任何后续代码执行 CONFIG.apiBase = 'http://test' 或 CONFIG = {} 都能改掉它——连 Object.freeze() 都拦不住顶层赋值,因为冻结只作用于对象属性,不阻止变量重绑定。
Object.defineProperty 怎么锁死全局变量绑定
关键在于把配置项定义在全局对象(window 或 globalThis)上,并设置 writable: false + configurable: false。这样既禁止重新赋值,也禁止删除或重定义该属性。
实操建议:
- 必须指定
value(不能写get),否则无法阻止顶层赋值(CONFIG = null仍会成功) - 不要设
enumerable: false,否则for...in和Object.keys()看不见它,调试和工具链可能出问题 - 浏览器环境优先用
globalThis,Node.js 里globalThis也已稳定支持
示例:
const config = { apiBase: 'https://api.example.com', timeout: 5000 };
Object.defineProperty(globalThis, 'CONFIG', {
value: config,
writable: false,
enumerable: true,
configurable: false
});
为什么 Object.freeze(config) 还不够
Object.freeze() 只冻结对象自身属性的可写性和可配置性,但对全局变量本身毫无约束。下面这些操作依然生效:
-
CONFIG = { apiBase: 'hacked' }—— 直接替换整个变量值 -
delete globalThis.CONFIG—— 如果没设configurable: false,这个操作会成功 -
Object.defineProperty(globalThis, 'CONFIG', {...})—— 如果没设configurable: false,还能重定义
所以必须组合使用:Object.freeze(config) 锁内部,Object.defineProperty 锁外部绑定。
常见报错和兼容性注意点
在严格模式下尝试修改 writable: false 的属性会抛出 TypeError: Cannot assign to read only property;非严格模式则静默失败——务必开启严格模式('use strict')才能及时暴露问题。
其他要点:
- ESM 模块中无法直接向
globalThis添加属性(会报Cannot set property CONFIG of #<object> which has only a getter</object>),需确保运行在 CommonJS 或顶层脚本环境 - Vite / Webpack 开发服务器有时会注入自己的全局变量逻辑,如果发现
CONFIG被覆盖,检查是否在 HMR 热更新时重复执行了 defineProperty - 测试是否生效:执行
CONFIG = null后打印CONFIG,应仍为原对象
真正难防的是引用泄漏——只要有人拿到 CONFIG 的引用并调用 Object.assign(CONFIG, {...}),内部数据还是可能被改。如果需要彻底不可变,得用 structuredClone() 或深冻结库,但那是另一层问题了。










