IIFE不是模块系统,而是ES6前最务实的模块化实践:通过函数作用域封装私有状态,return对象暴露有限接口,实现命名空间隔离、依赖注入与平滑过渡到ESM。

立即执行函数(IIFE)不是模块系统,但它在 ES6 import/export 出现之前,是前端实现模块化思想最广泛、最务实的手段。它不依赖构建工具或运行时环境,靠纯 JavaScript 作用域机制,把代码“包”起来,再有选择地“露出来”。
封装私有状态,暴露有限接口
一个 IIFE 内部可以定义变量、函数等,全部默认私有;通过 return 返回一个对象,就相当于导出 API。外部只能访问这个对象上的属性和方法,无法触碰内部实现细节。
- 比如计数器模块:内部用
let count = 0存状态,只暴露inc()和get() - 比如配置模块:内部解析 JSON 或合并默认值,只返回只读的
config对象 - 关键点:返回的对象里不要直接返回原始私有变量(避免被意外修改),必要时用 getter 封装
多个模块协同,避免全局命名冲突
早期一个页面常引入多个第三方脚本(如轮播图、表单校验、统计 SDK)。若各自把变量挂到 window 下,极易重名覆盖。IIFE 让每个模块运行在独立作用域中,互不干扰。
- 每个模块自成一体:
var slider = (function(){...})();、var validator = (function(){...})(); - 即使两个模块都用了
var utils = {...},也不会冲突——因为它们分别在各自的函数作用域里 - 这种“命名空间隔离”是当时事实上的模块标准,jQuery 插件生态就大量基于此模式
支持依赖注入与环境适配
IIFE 可接收参数,天然适合传入依赖(如 window、document、其他模块),还能做运行时判断,让模块更健壮。
- 常见写法:
(function(global, doc) { ... })(typeof window !== 'undefined' ? window : globalThis, document); - 既兼容浏览器,也预留 Node.js 环境适配空间(虽然 Node 原生支持 CommonJS)
- 可传入已有的模块实例,实现手动“依赖注入”,例如:
(function($){ $('.btn').on('click', ...); })(jQuery);
向现代模块平滑过渡的桥梁
很多老项目中的 IIFE 模块,结构上已具备清晰的“输入-逻辑-输出”特征,改造为 ES Module 成本很低:
- 把
return { init, destroy }改成export { init, destroy } - 把传入的
jQuery参数改成import $ from 'jquery' - 原来靠顺序加载隐式依赖,现在显式
import,可读性和可维护性直线上升
它不是过时的技巧,而是模块化演进过程中真实落地的思维范式——用最小语言特性,解决最大工程问题。

















