JavaScript可通过闭包实现模块系统,用IIFE创建私有作用域,define注册模块(含依赖与工厂函数),require按需递归加载并缓存结果,支持依赖解析与防重复执行,但不支持异步、路径解析及循环依赖检测。

JavaScript 中可以通过闭包封装模块定义与加载逻辑,避免全局污染,同时支持按需加载和依赖管理。核心思路是用立即执行函数(IIFE)创建私有作用域,维护一个模块注册表,并提供 define 和 require 接口。
模块注册:define 方法
定义模块时,把模块名、依赖列表和工厂函数存入内部缓存。工厂函数只在首次 require 时执行,返回模块导出值。
- 模块名作为唯一 key,防止重复注册
- 依赖数组用于提前解析,确保执行顺序
- 工厂函数接收已加载的依赖作为参数,返回模块对象
模块加载:require 方法
require 接收模块名或依赖列表,递归加载未初始化的依赖,再执行当前模块工厂函数,缓存并返回结果。
- 检查模块是否已加载,避免重复执行
- 对每个依赖调用自身,实现深度优先加载
- 将依赖的返回值按顺序传入工厂函数
简单实现示例
以下是一个轻量级模块加载器原型:
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
立即学习“Java免费学习笔记(深入)”;
const ModuleLoader = (function () {
const modules = {};
function define(name, deps, factory) {
modules[name] = { deps, factory, exports: null, loaded: false };
}
function require(name) {
if (typeof name === 'string') {
const mod = modules[name];
if (!mod) throw new Error(`Module "${name}" not defined`);
if (mod.loaded) return mod.exports;
// 加载依赖
const args = mod.deps.map(depName => require(depName));
// 执行工厂函数并缓存
mod.exports = mod.factory(...args);
mod.loaded = true;
return mod.exports;
}
// 批量 require,返回模块对象数组
return name.map(require);
}
return { define, require };
})();
使用方式
先定义模块,再通过 require 使用:
ModuleLoader.define('utils', [], () => ({ log: console.log }));ModuleLoader.define('main', ['utils'], (utils) => { utils.log('loaded'); });ModuleLoader.require('main');
这个结构不依赖构建工具,适合学习模块原理或极简场景,但不支持异步加载、路径解析或循环依赖检测。

















