JavaScript CommonJS 和 ES Module 区别
你或许在写前端代码时,会碰到 require 和 import 这两个常用的代码片段,它们就像两种不同的“快递收件规则”,对应着 JavaScript 里两种主流的模块管理方式——CommonJS 和 ES Module(简称 ES 模块)。这两种规则到底有什么不一样?咱们用日常买奶茶的例子来拆解,就会特别好懂。
快递发出的时机:“现做现发” vs “提前备货”
咱们先从“什么时候准备好要发送的内容”说起,这是两种规则最核心的区别,也是初学者最容易踩坑的地方。

CommonJS 用的是 require 导入,它的规则是“现用现取”,就像你点奶茶时,只有下单(代码运行到 require 这一行),门店才开始制作奶茶。比如你写代码:
`javascript
const drink = require('milk-tea');
console.log(drink);
`
只有代码运行到第二行时,才会去加载 milk-tea 这个模块,就像下单后门店才做奶茶,必须等,没法提前拿到成品。
而 ES Module 用的是 import 导入,它的规则是“提前备货”,就像门店提前把做好的奶茶摆在柜台,你一进店(代码运行),奶茶已经准备好了。比如:
`javascript
import drink from 'milk-tea';
console.log(drink);
`
浏览器或 Node.js 在运行代码之前,就会自动把所有 import 的模块加载完成,不管你有没有用到这个变量,都会提前准备好,不会等到用到才去取。
适用场景:“外卖小哥专用” vs “商场专柜专用”
就像不同的快递规则适配不同的配送场景,这两种模块也有专属的适用环境。
CommonJS 更适合 Node.js 的后端场景,它是 Node.js 刚诞生时自带的模块管理方案,就像专为外卖小哥设计的配送规则——“先点单再配餐,适合随时调整的需求”。比如你写后端接口时,有时候需要根据用户的请求动态加载不同的工具函数,用 CommonJS 就很方便,它能在代码运行过程中随时动态导入模块。
而 ES Module 是后来随着 JavaScript 标准升级推出的,更适合前端的浏览器场景,就像商场专柜的固定备货规则——“提前摆好所有商品,方便快速浏览”。现在几乎所有现代浏览器都支持 ES Module,前端开发用它写代码,还能借助工具实现“按需加载”:比如页面只需要用到首页的模块,就只加载这部分代码,不会把整个项目的代码都塞给用户,能大幅提升网页加载速度。
输出内容的“稳定性”:“复制奶茶” vs “共享奶茶制作机”
你导入的内容是“复制一份”还是“共享同一个原件”,这也是两者的关键区别,咱们继续用奶茶举例。
CommonJS 导入的是模块的“值拷贝”,就像你点了一杯珍珠奶茶,拿到的是一杯做好的成品,之后你在代码里修改这个奶茶,不会影响门店里的其他同款奶茶——它是一个独立的副本。比如:
`javascript
// 模块 milk-tea.js
let pearls = 5;
module.exports = { pearls };
// 主文件
const drink = require('./milk-tea');
drink.pearls = 10;
const anotherDrink = require('./milk-tea');
console.log(anotherDrink.pearls); // 输出还是5,因为改的是副本
`
而 ES Module 导入的是“值的引用”,就像你拿到的是门店珍珠奶茶制作机的钥匙,不管谁用这台机器,做出来的珍珠数量是全局统一的——任何地方修改这个值,所有引用它的地方都会跟着变。比如:
`javascript
// 模块 milk-tea.js
export let pearls = 5;
// 主文件
import { pearls } from './milk-tea.js';
pearls = 10;
import { pearls as anotherPearls } from './milk-tea.js';
console.log(anotherPearls); // 输出10,因为是同一个引用
`
简单来说,CommonJS 像日常点外卖的灵活规则,适合随时调整的场景;ES Module 像商场专柜的标准化规则,适配现代前端的高效需求。现在前端项目大多用 ES Module,后端 Node.js 也开始支持它,但了解两者的区别,能帮你在写代码时少踩坑,选对合适的方式。