JS模块化核心是函数作用域隔离变量+闭包维持私有状态+显式返回接口;IIFE创建独立词法环境,工厂函数生成多实例,ES6模块分层组织,需注意闭包内存泄漏风险。

JS 中作用域与闭包综合应用设计模块化代码,核心是利用函数作用域隔离变量 + 闭包保持私有状态 + 显式返回公共接口。这不是语法糖,而是运行时机制的自然结果:只要内部函数引用了外部变量,并被返回到外层作用域使用,就自动形成模块。
用立即执行函数封装私有作用域
最经典、兼容性最好的写法是 IIFE(立即执行函数表达式),它创建独立词法环境,避免污染全局:
- 把所有变量和函数声明在函数体内,它们天然成为“私有”成员
- 只通过 return 对象暴露需要对外使用的函数或值
- 返回的对象中每个方法都形成闭包,持续持有对私有数据的引用
示例:
const Counter = (function() {let count = 0;
function increment() { count++; }
function get() { return count; }
return { increment, get };
})();
Counter.increment();
console.log(Counter.get()); // 1
用工厂函数生成多个独立模块实例
当需要多个彼此隔离的模块(比如多个计数器),应使用普通函数而非 IIFE —— 每次调用都新建一套闭包环境:
- 函数接收初始化参数,内部定义私有变量和逻辑
- 返回一个对象(或函数),其中方法共享该次调用的私有状态
- 两次调用产生的两个对象,其内部变量完全不互相干扰
示例:
function createLogger(prefix) {let callCount = 0;
return {
log(msg) {
console.log(`[${prefix}] #${++callCount}: ${msg}`);
},
};
}
const userLog = createLogger('USER');
const adminLog = createLogger('ADMIN');
userLog.log('login'); // [USER] #1: login
adminLog.log('delete'); // [ADMIN] #1: delete
结合 ES6 模块系统做分层组织
现代项目中,闭包模块通常作为底层封装,再由 ES6 的 import/export 做顶层组织:
- 每个 .js 文件是一个 ES6 模块,天然具有作用域隔离
- 文件内可用闭包封装复杂逻辑(如缓存、状态机、配置管理)
- export default 或 export named 暴露干净接口,隐藏实现细节
例如一个带缓存的 fetch 封装:
const createCachedFetcher = () => {const cache = new Map();
return async function(url) {
if (cache.has(url)) return cache.get(url);
const res = await fetch(url);
const data = await res.json();
cache.set(url, data);
return data;
};
};
export const cachedFetch = createCachedFetcher();
注意闭包带来的生命周期与内存影响
闭包让变量不被释放,这既是优势也是责任:
- 长期持有 DOM 引用、大型数组或未清理的事件监听器,容易引发内存泄漏
- 若模块需销毁(如组件卸载),应在公共 API 中提供 clear / destroy 方法,主动解除引用
- 避免在循环或高频回调中无意创建大量闭包(如 for 循环里直接 return function)
安全做法示例:
function createResourceManager() {let data = null;
let cleanup = () => {};
return {
set(d) { data = d; },
get() { return data; },
onDestroy(fn) { cleanup = fn; },
destroy() {
cleanup();
data = null;
},
};
}


















