ES Modules 通过作用域隔离与显式导出实现天然模块私有化:未 export 的变量、函数、类均不可外部访问;推荐默认导出主接口、按需导出工具,避免 export *;可结合类私有字段(#)强化封装,并警惕动态挂载等破绽。

ES Modules 本身不提供“模块级私有变量”的语法机制,但通过作用域隔离 + 默认导出控制,天然实现了模块私有化封装——模块内部的变量、函数、类,只要不显式 export,就对外不可见、不可访问。
模块作用域就是天然的私有边界
每个 .js 文件在 ES Modules 环境中是一个独立模块作用域。这意味着:
- 用
const/let/var声明的顶层变量,仅在本文件内有效 - 函数内部定义的变量、闭包捕获的值,完全无法从外部触及
- 即使导出了某个函数,它内部引用的私有变量仍被闭包保护,不会暴露
只导出需要暴露的接口
封装的关键不是“怎么藏”,而是“只放行该放行的”。推荐做法是:
- 用
export default暴露一个干净的主对象(如类、工厂函数或命名空间对象) - 用
export按需导出少量工具函数或常量,避免全量导出 - 绝不使用
export * from './xxx'模糊边界,除非明确需要透传
例如:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
立即学习“Java免费学习笔记(深入)”;
/* utils.js */
const API_BASE = 'https://api.example.com';
const cache = new Map();
<p>function request(url) {
return fetch(API_BASE + url);
}</p><p>export function getUser(id) {
const key = <code>user-${id}</code>;
if (cache.has(key)) return Promise.resolve(cache.get(key));
return request(<code>/users/${id}</code>).then(res => res.json())
.then(data => {
cache.set(key, data);
return data;
});
}</p><p>// API_BASE 和 cache 都未导出 → 外部完全无法访问配合类私有字段强化封装(ES2022+)
如果模块导出的是类,可进一步用 # 私有字段/方法加固内部状态:
-
#token、#retryCount等字段只能在类内部访问 - 即使用户拿到实例,也无法读写或调用以
#开头的成员 - 这比靠命名约定(如
_private)或闭包模拟更安全、更可维护
示例:
/* auth.js */
export default class AuthService {
#token = null;
#expiresAt = 0;
<p>login(credentials) {
// ...设置 #token 和 #expiresAt
}</p><p>get isAuthenticated() {
return this.#token && Date.now() < this.#expiresAt;
}</p><p>// #token 无法从外部访问:new AuthService().#token → SyntaxError
}避免常见封装破绽
看似封装了,实际可能被绕过。注意这些陷阱:
- 不要在导出对象上动态挂载私有数据(如
instance._internal = {...}) - 避免将私有函数作为参数传给外部回调,导致意外泄露引用
- 慎用
export { something as default }这类重命名导出,易模糊责任归属 - 构建工具(如 Vite、Webpack)默认支持 tree-shaking,未导出的代码会被自动剔除,这是额外的安全层

















