JavaScript中无原生模块语法时,开发者用IIFE+闭包模拟模块:封装私有变量/函数,仅通过返回对象导出公共API,支持单函数、构造函数或增强全局对象等导出形式,并为CommonJS和ES Module提供思想源头。

JavaScript 中没有原生的模块语法(ES5 及之前),开发者常通过 立即执行函数表达式(IIFE) + 闭包 模拟模块作用域,并控制哪些变量/函数对外可见——这就是“闭包实现模块导出”的核心思路。
用闭包封装私有作用域
IIFE 创建独立作用域,内部声明的变量默认不可被外部访问。闭包让内部函数能持续访问这些变量,同时只暴露需要导出的接口:
var MyModule = (function() {
// 私有变量和函数
var count = 0;
function privateHelper() {
return count * 2;
}
<p>// 返回一个对象,作为“导出”的公共 API
return {
increment: function() {
count++;
return count;
},
getValue: function() {
return count;
}
// privateHelper 不在返回对象中 → 外部无法调用
};
})();</p>调用 MyModule.increment() 会修改闭包内私有的 count,但外部代码无法直接读写 count 或调用 privateHelper。
导出方式支持多种形态
闭包返回的对象不是唯一选择,可根据需要灵活导出:
立即学习“Java免费学习笔记(深入)”;
-
导出单个函数:适合工具类模块,如
var uuid = (function(){...})(); -
导出构造函数:返回一个函数,供
new实例化,内部状态仍被闭包保护 -
增强已有对象:传入全局对象(如
window或命名空间对象),向其添加属性,避免污染全局
与 CommonJS / ES Module 的关系
这种模式是早期浏览器端模块化的事实标准(如 jQuery 插件、早期 Lodash),也是 CommonJS(Node.js)和 ES Module 设计的思想源头:它们都依赖“作用域隔离 + 显式导出”原则。区别在于:
- 闭包模块需手动管理依赖(通过参数传入其他模块)
- CommonJS 使用
module.exports和require,运行时解析 - ES Module 使用
export/import,静态编译期分析
现代打包工具(如 Webpack)在处理旧式闭包模块时,也能识别并将其纳入依赖图。
注意命名空间污染和依赖显式性
纯闭包模块容易隐式依赖全局变量。推荐写法是把依赖作为参数传入 IIFE:
var MyModule = (function($, utils) {
// 明确依赖 jQuery 和 utils 模块
return {
init: function() {
$(document).ready(utils.log('ready'));
}
};
})(jQuery, window.utils);
这样既保持闭包封装,又让依赖清晰可查,也便于测试和替换依赖。


















