JavaScript中无法靠exports限制修改权限,需结合模块封装性、命名约定与设计策略:用闭包隐藏状态,导出前冻结对象、定义getter/setter、分层导出接口,实现逻辑上的只读与受控访问。

不能靠 exports 本身限制修改权限,它只是导出机制,不提供访问控制。真正起作用的是 JavaScript 的模块封装性 + 命名约定 + 代码设计策略。
用闭包封装单例状态,只暴露受控接口
把单例的私有数据放在模块作用域内,不直接挂到 exports 上,只导出经过封装的方法:
- 定义一个立即执行函数或模块级变量存储真实状态(如
let _instance = null) - 导出的
getInstance()返回对象时,返回一个新对象或 Proxy,避免暴露原始引用 - 关键字段不设为可写/可配置(用
Object.defineProperty或Object.freeze)
导出冻结的对象实例(适合只读场景)
如果单例只需被读取,导出前调用 Object.freeze():
const singleton = {
config: { timeout: 5000 },
version: '1.2.0'
};
Object.freeze(singleton);
exports.instance = singleton;
注意:Object.freeze 是浅冻结,嵌套对象仍可修改;如需深冻结,需手动递归或使用第三方工具。
用 getter/setter 控制属性访问
在导出对象上定义访问器属性,拦截读写行为:
- 对敏感字段只提供
get,不提供set,或set中加入校验逻辑 - 例如:
Object.defineProperty(exports, 'data', { get() { return _privateData; } }) - 避免直接导出可变对象字面量,改用动态定义的属性
结合 ES6 模块默认导出与命名导出做分层控制
CommonJS 的 exports 是对象,ES6 模块更灵活。若环境支持,优先用:
-
export default Object.freeze({...})—— 默认导出只读实例 -
export const getInstance = () => {...}—— 提供带逻辑的获取方式 -
export const reset = () => {...}—— 仅限内部或测试使用的管理函数,不导出修改入口
本质上,JavaScript 没有真正的“私有”或“只读导出”,但通过封装 + 冻结 + 访问器 + 约定,能有效防止意外修改,提升模块健壮性。










