common.js和es6中模块引l入的区别?

CommonJS(CJS)和 ES6 模块(ESM)是 JavaScript 中两套完全不同的模块规范 ,它们在设计理念、加载机制、运行行为上都有本质区别。

下面从 核心差异 → 运行机制 → 实战影响​ 系统讲清楚。


一、最核心的 10 个区别(速览表)

对比项 CommonJS ES6 Module
诞生背景 Node.js 社区规范 ECMAScript 官方标准
加载方式 运行时同步加载​ 编译期静态分析​
导入语法 require() import
导出语法 module.exports export
是否静态 ❌ 动态 ✅ 静态
是否支持 Tree Shaking ❌ 不支持 ✅ 支持
模块输出 值的拷贝​ **值的实时引用(活绑定)**​
this 指向 module.exports undefined
循环依赖 返回"未完成副本" 支持实时绑定
顶层 await ❌ 不支持 ✅ 支持(ES2022)

二、加载机制的本质差异(最重要)

✅ CommonJS:运行时加载(动态)

复制代码
const fs = require('fs'); // 执行到这里才加载
  • 模块在 代码执行阶段​ 才加载

  • require是一个普通函数

  • 可以写在条件判断里:

    if (Math.random() > 0.5) {
    require('./a');
    } else {
    require('./b');
    }

✅ 灵活

❌ 无法静态分析


✅ ES Module:编译期静态解析

复制代码
import fs from 'fs';
  • 在 代码执行前​ 就被解析

  • import是语法,不是函数

  • 不能动态写在 if 里

    // ❌ 报错
    if (true) {
    import a from './a';
    }

✅ 可被引擎提前分析

✅ 支持优化(Tree Shaking)


三、导出的值:拷贝 vs 实时绑定(非常关键)

1️⃣ CommonJS:值的拷贝

复制代码
// a.js
let count = 1;
module.exports = { count };

// main.js
const { count } = require('./a');
count++; 
console.log(count); // 2

❗ 导出的 count 是值的快照


2️⃣ ES Module:实时绑定(Live Binding)

复制代码
// a.mjs
export let count = 1;

// main.mjs
import { count } from './a.mjs';
console.log(count); // 1

如果 a.mjs 里改了:

复制代码
count++;

main.mjs 中 自动变化。

✅ 这是 ESM 最反直觉但最重要的特性


四、this 指向差异

复制代码
// CommonJS
console.log(this === module.exports); // true

// ES Module
console.log(this); // undefined

✅ ESM 强制严格模式

✅ 没有 module 对象


五、循环依赖的处理方式

CommonJS:返回"半成品"

复制代码
// a.js
exports.loaded = false;
const b = require('./b');
exports.loaded = true;

// b.js
exports.loaded = false;
const a = require('./a');
console.log(a.loaded); // false

❌ 可能读到未初始化的值


ES Module:支持实时绑定

复制代码
// a.mjs
import { bLoaded } from './b.mjs';
export let aLoaded = false;
aLoaded = true;

// b.mjs
import { aLoaded } from './a.mjs';
export let bLoaded = false;
bLoaded = true;

✅ 双方都能拿到最终正确值


六、Tree Shaking 为什么只支持 ESM?

复制代码
// utils.js
export function a() {}
export function b() {}

// main.js
import { a } from './utils.js';

✅ 打包工具能确定 b没被用

✅ 可以安全删除

而 CommonJS:

复制代码
module.exports = { a, b };

❌ 无法确定哪些属性会被访问

❌ 不敢删


七、Node.js 中的现实差异

项目 CommonJS ES Module
文件后缀 .js .mjs或 "type": "module"
require ✅ ❌(默认)
import ❌ ✅
__dirname ✅ ❌(需手动拼)
顶层 await ❌ ✅

Node.js 中混合使用:

复制代码
// ESM 中引入 CJS
import cjs from './cjs.cjs';

// CJS 中引入 ESM(Node 18+)
import('./esm.mjs').then(...);

八、一句话总结

**CommonJS 是为服务端设计的"运行时模块系统",

ES Module 是为通用 JavaScript 设计的"编译期模块标准"。**

✅ 新项目优先用 ES Module​

✅ **库开发必须支持 ESM(才能 Tree Shaking)**​

✅ Node 生态正在全面迁移到 ESM

相关推荐
派小心.1 分钟前
多端数据分析平台的漏斗可以跨端搭建吗?5 步搭出跨端转化漏斗
大数据·运维·服务器·前端·数据分析
IT_陈寒12 分钟前
为什么我的React组件一直在意外重渲染?
前端·人工智能·后端
Su米苏15 分钟前
基于 Token 预算的上下文压缩控制器(Context Compaction Controller)
前端·数据库·人工智能
骇客野人15 分钟前
Java 开发组件大全覆盖后端主流技术栈(基础、Web、ORM、中间件、微服务、安全、工具、测试、运维、信创适配常用组件)
java·前端·中间件
谢亮_vipxieliang20 分钟前
深入理解 JavaScript 数据类型与类型转换
开发语言·javascript·ecmascript
风骏时光牛马1 小时前
大模型底层架构与推理流程AI源码深度剖析
前端
程序员Sunday10 小时前
JavaScript 事件循环面试题,宏任务与微任务怎么执行|Sunday面试指南
开发语言·javascript·面试·校招·事件循环·程序员sunday
Setsuna_F_Seiei10 小时前
前端转型 Agent 开发 06 之 Agent Memory 记忆系统(让 Agent 更智能,更懂你)
前端·agent·ai编程
zhangzeyuaaa11 小时前
Ruby 多线程、GVL(GIL)与 Mutex 完全指南
开发语言·前端·ruby
默_笙11 小时前
🌊 向量库和 ES 都查不出"关系",我只好给奶茶建了一张人脉网
前端·javascript