惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

IT之家
IT之家
Y
Y Combinator Blog
月光博客
月光博客
Blog — PlanetScale
Blog — PlanetScale
GbyAI
GbyAI
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
博客园 - 三生石上(FineUI控件)
S
SegmentFault 最新的问题
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
美团技术团队
雷峰网
雷峰网
酷 壳 – CoolShell
酷 壳 – CoolShell
Last Week in AI
Last Week in AI
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
有赞技术团队
有赞技术团队
博客园 - 司徒正美
V
Visual Studio Blog
小众软件
小众软件
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
T
Tailwind CSS Blog
Apple Machine Learning Research
Apple Machine Learning Research
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
A
About on SuperTechFans
The Cloudflare Blog

博客园 - lzhdim

25个每个开发人员都应该掌握的JavaScript 数组方法 20260831 - 个人小作品更新 C#使用SQLite数据库例子 - 开源研究系列文章 20260830 - 个人小作品更新 20260829 - 个人小作品更新 13、JavaScript事件循环机制 - JavaScript学习系列文章 首款媲美分体水冷的一体水冷!微星CORELIQUID E15 360水冷散热器评测:目前为止 锐龙9 9950X3D最强性能释放 JavaScript常见的内存泄露问题 - JavaScript学习系列文章 C#开发的颜色取色器 - 开源研究系列文章 - 个人小作品 成长环境 - 我的闪存 提高 SQL 语句执行速度的方法 JavaScript安全最佳实践 关闭iPhone一些默认设置,让iPhone更流畅 20260814 - 个人小作品更新 JavaScript对象与元编程 20260812 - 个人小作品更新 Markdown 语法完全指南 C# 通过 Windows API 实现进程内存读写操作 JavaScript 函数进阶课题 C#开发的基于钩子技术监测键鼠事件的例子 - 开源项目研究文章 JavaScript异步编程的演进 近十年最帅风冷!酷冷至尊V8 ACE 3DHP散热器评测:单塔能干翻双塔 20260723 - 个人小作品更新 C# 中读取CPU、硬盘和内存温度 雷柏VT3s MAX鼠标评测:中小手型用户也没有被遗忘 顶尖性能的小号电竞鼠标来了 JavaScript 中的原型与继承 1分钟查清局域网所有IP 20260714 - 个人小作品更新 WorkBuddy 完整教程手册 专为AI而生的企业级QLC SSD!长江存储PE501 61.44TB评测:超过1PB的写入测试
JavaScript 模块化系统
lzhdim · 2026-08-10 · via 博客园 - lzhdim

一、为什么需要模块化?

想象一下你正在写一个大型项目, 所有代码都堆在一个文件里: 

// 可怕的全局变量地狱var utils = {...};var api = {...};var componentA = {...};var componentB = {...};
// 20000行之后...function doSomething() {    //谁知道这个函数会不会覆盖前面的定义?}

这种写法有几个致命问题: 

  • 命名冲突: 变量和函数都在全局作用域,容易覆盖

  • 依赖混乱:不知道代码执行前需要加载哪些依赖

  • 难以维护: 代码组织像意大利面条,牵一发而动全身

模块化就是为了解决这些问题而生的! 它让我们可以: 

  • 将代码拆分成独立的小文件(模块)

  • 明确声明依赖关系

  • 避免污染全局命名空间

  • 方便代码复用和维护


二、CommonJS

CommonJS 是 Node.js 采用的模块系统, 语法非常简单: 

// math.jsfunction add(a, b) {    return a + b;}
function subtract(a, b) {    return a - b;}
//导出模块module.exports = {    add,    subtract};
//或者也可以这样导出exports.add = add;exports.subtract = subtract;

使用的时候如下所示:

// app.jsconst math = require('./math.js');
console.log(math.add(2, 3)); console.log(math.subtract(5, 2)); 

它有什么特点呢?

  • 同步加载: 模块在 require 时同步加载并执行.

  • 缓存机制: 模块首次加载后会被缓存, 后续 require 直接返回缓存.

  • 值拷贝: 导出的是值的拷贝(对于原始类型), 修改不会影响原模块.

三、ES Modules

ES Modules(简称 ESM)是 ECMAScript 2015(ES6)引入的官方模块系统, 现在已经被现代浏览器和 Node.js 支持. 

基本语法: 

// math.jsexport function add(a, b) {    return a + b;}
export function subtract(a, b) {    return a - b;}
// 或者默认导出export default {    add,    subtract};

导入模块: 

// 命名导入import { add, subtract } from './math.js';
// 默认导入import math from './math.js';
// 混合导入import math, { add } from './math.js';
// 整体导入import * as math from './math.js';

与CommonJS的区别: 

  • 静态分析: ESM 的 import/export 必须在顶层作用域, 可以被静态分析

  • 动态绑定: ESM 导出的是值的引用(活的绑定), 修改会影响所有导入

  • 异步加载: ESM 在浏览器中是异步加载的

// counter.jsexport let count = 0;
export function increment() {    count++;}
// app.jsimport { count, increment } from './counter.js';
console.log(count); // 0increment();console.log(count); //1(ESM是动态绑定)


在浏览器里如何加载模块呢?

<!-- 传统脚本 --><script src="app.js"></script>
<!-- 模块脚本 --><script type="module" src="app.js"></script>

关键区别: 

  • 模块默认defer, 在文档解析完成后执行

  • 模块有独立作用域, 不会污染全局

  • 模块需要 CORS 配置, 不能使用 file:// 协议

  • 模块会自动应用严格模式


四、按需加载

静态导入(import ... from ...)必须在模块顶层, 但有时候我们需要按需加载: 

// 普通导入import('./math.js').then(math => {    console.log(math.add(2, 3));});
// 配合 async/awaitasync function calculate() {    const math = await import('./math.js');    console.log(math.add(2, 3));}

条件加载: 

if (user.isAdmin) {    import('./admin.js').then(...);}

预加载: 

<link rel="modulepreload" href="critical-module.js">

组合使用: 

Promise.all([    import('./moduleA.js'),    import('./moduleB.js')]).then(([moduleA, moduleB]) => {    // 两个模块都加载完成});