← [ BACK_TO_NOTES ]

ES6模块导入导出方式

ESM 的 import / export 语法与模块边界。

#dev #concept #growing #javascript #ecmascript

[!info] related notes

ES6 模块 (ESM)

一句话定义

ESM 是 ECMAScript 原生的模块系统,通过静态的 import / export 语法实现模块间依赖声明,支持静态分析和 Tree Shaking。

核心机制 / 工作原理

  1. 被宿主按 ESM 加载的文件具有独立模块作用域,并自动采用严格模式;普通脚本文件并不因此自动成为模块。
  2. 在同一加载环境中,同一模块标识通常只求值一次;Node ESM 按 URL 缓存,不同查询参数或片段可形成不同实例。
  3. 静态 import 声明让依赖可在执行前分析;模块解析、加载与求值仍由宿主完成。Tree Shaking 是工具优化,还受副作用和配置影响。
  4. ESM 导出的是 活绑定 (live bindings):导入方读取的是关联的导出绑定,不能直接给这个导入绑定赋值;导出对象的属性是否可改是另一回事。

命名导出 / 导入

// ---- math.js ----
export const PI = 3.14159;
export function add(a, b) { return a + b; }

// ---- app.js ----
import { PI, add } from './math.js';
import { add as sum } from './math.js'; // 重命名导入
import * as math from './math.js';       // 命名空间导入

默认导出 / 导入

// ---- logger.js ----
export default function log(msg) {
  console.log(msg);
}

// ---- app.js ----
import log from './logger.js'; // 名字可以随便取
import myLog from './logger.js';

重新导出 (Re-export)

export { add } from './math.js';              // 转发命名导出
export { default as Logger } from './logger.js'; // 转发默认导出
export * from './math.js';                     // 转发所有命名导出(不含 default)
export * as math from './math.js';             // ES2020: 命名空间再导出

动态导入

const module = await import('./heavy-module.js');
module.doSomething();

// 条件导入
if (needsChart) {
  const { Chart } = await import('./chart.js');
  new Chart(canvas);
}

活绑定 (Live Bindings)

// counter.js
export let count = 0;
export function increment() { count++; }

// app.js
import { count, increment } from './counter.js';
console.log(count); // 0
increment();
console.log(count); // 1 — 活绑定,看到的是最新值

循环依赖行为

ESM 会先建立模块之间的绑定,再按依赖求值。循环本身不必报错,但访问尚未初始化的 let / const / class 绑定会触发暂时性死区错误,不会返回 CJS 式的“部分导出对象”。

// a.mjs
import { b } from './b.mjs';
export const a = 'a';
console.log('b in a:', b);

// b.mjs
import { a } from './a.mjs';
export const b = 'b';
console.log('a in b:', a);

分别保存为两个文件后运行 node a.mjs:b.mjs 读取 a 时抛出 ReferenceError,两条日志不会按原例注释正常输出。把读取延后到初始化完成之后,或消除这条循环,才可能安全执行。

ESM vs CJS 快速对比

维度ESMCJS
语法import / exportrequire() / module.exports
依赖表达静态声明,另支持 import()require() 运行时调用
导入结果活绑定或模块命名空间module.exports 值,对象不自动复制
Tree Shaking静态结构利于工具分析,仍受副作用影响分析较难,能力依工具而定
浏览器原生支持(<script type="module">)不支持
循环依赖提前读取未初始化绑定会报错可能拿到不完整导出

边界与常见误解

  • import 必须在顶层:常规 import 不能在 if 或函数内使用(静态分析限制),条件加载请用 import()。
  • 默认导出不是命名导出的语法糖:一个模块可以同时有默认导出和命名导出,它们是不同的导出槽位。
  • Node.js 中 ESM 需要配置:明确方式是使用 .mjs,或为 .js 在最近的 package.json 中设置 "type": "module";较新 Node 也可能进行语法检测,不宜依赖隐式判定。

示例运行前提

前面的 .js 文件示例按文件注释分别保存,并在 Node 项目中设置 "type": "module";动态导入部分是接口示意,需自行提供对应模块和变量。循环示例使用 .mjs,不依赖包配置。

参考资料

创建于 2025/1/1 更新于 2026/10/6
Digital Biome
Access

键盘导航

j / k / ↑ / ↓
选择对象
Enter / o
打开选择
/ 或 Ctrl+K
全站搜索
i / f / 1–4
筛选当前列表
g → h / l / p / t / a
首页 / 笔记 / 项目 / 工具 / About
r → 1–9
打开所选对象的关联
u
返回上一页
Esc
关闭浮层 / 取消命令;输入框内清空文本