ES Module(ESM)是 JavaScript 的官方模块系统,提供了静态的模块导入和导出机制。
// 命名导出
export const name = 'Alice';
export function greet() {
return 'Hello';
}
export class User {
constructor(name) {
this.name = name;
}
}
// 或者统一导出
const name = 'Alice';
function greet() {
return 'Hello';
}
export { name, greet };
// 重命名导出
export { name as userName, greet as sayHello };
// 命名导入
import { name, greet } from './module.js';
import { name as userName, greet as sayHello } from './module.js';
// 导入所有
import * as module from './module.js';
module.name;
module.greet();
// 默认导入
import defaultExport from './module.js';
// 混合导入
import defaultExport, { namedExport } from './module.js';
import defaultExport, * as namedExports from './module.js';
// 默认导出
export default function greet() {
return 'Hello';
}
// 或者
function greet() {
return 'Hello';
}
export default greet;
// 默认导出类
export default class User {
constructor(name) {
this.name = name;
}
}
// 编译时就能知道导入了什么
import { func1 } from './utils.js';
// func2 不会被包含在打包结果中(如果未使用)
// 不需要 'use strict'
// 自动启用严格模式
console.log(this); // undefined
// module.js
let count = 0;
export function increment() {
count++;
return count;
}
// main.js
import { increment } from './module.js';
import { increment as inc } from './module.js';
increment(); // 1
inc(); // 2 (共享同一个 count)
使用 import() 函数实现动态导入:
// 动态导入返回 Promise
import('./module.js')
.then(module => {
module.default();
module.namedExport();
});
// 使用 async/await
async function loadModule() {
const module = await import('./module.js');
module.default();
}
// 条件导入
if (condition) {
const module = await import('./module.js');
}
// 重新导出其他模块的内容
export { name, greet } from './module1.js';
export { default } from './module2.js';
export * from './module3.js';
// 重命名重新导出
export { name as userName } from './module1.js';
// utils/math.js
export function add(a, b) {
return a + b;
}
export function multiply(a, b) {
return a * b;
}
// utils/string.js
export function capitalize(str) {
return str.charAt(0).toUpperCase() + str.slice(1);
}
// utils/index.js (统一导出)
export * from './math.js';
export * from './string.js';
// 使用
import { add, capitalize } from './utils/index.js';
// config.js
const config = {
apiUrl: 'https://api.example.com',
timeout: 5000
};
export default config;
// 使用
import config from './config.js';
console.log(config.apiUrl);
// api/user.js
export function getUser(id) {
return fetch(`/api/users/${id}`);
}
export function createUser(data) {
return fetch('/api/users', {
method: 'POST',
body: JSON.stringify(data)
});
}
// 使用命名空间
import * as userAPI from './api/user.js';
userAPI.getUser(1);
userAPI.createUser({ name: 'Alice' });
// types.ts
export interface User {
name: string;
age: number;
}
export type Status = 'active' | 'inactive';
// 使用
import type { User, Status } from './types.js';
| 特性 | ES Module | CommonJS |
|------|-----------|----------|
| 加载时机 | 编译时 | 运行时 |
| 导入方式 | import | require() |
| 导出方式 | export | module.exports |
| 动态导入 | import() | require() |
| 顶层 this | undefined | module |
| 严格模式 | 自动启用 | 需手动启用 |
// CommonJS
const module = require('./module.js');
module.exports = { name: 'Alice' };
// ES Module
import module from './module.js';
export default { name: 'Alice' };
ES Module 可以处理循环依赖:
// a.js
import { b } from './b.js';
export const a = 'a';
// b.js
import { a } from './a.js';
export const b = 'b';
// 可以正常工作,但需要注意初始化顺序
import { func } from './utils.js';
import { func } from '../utils.js';
import { func } from '/src/utils.js';
import { func } from 'https://example.com/module.js';
import React from 'react';
import { map } from 'lodash';
.js 扩展名import { func } from './utils.js'; // 推荐
import { func } from './utils'; // 可能不工作
// 默认导出
export default function() {}
import func from './module.js';
// 命名导出
export function func() {}
import { func } from './module.js';
// 这些都会在顶部执行
func(); // 可以工作
import { func } from './module.js';
import { name } from './module.js';
name = 'Bob'; // TypeError: Assignment to constant variable
<!-- 使用 type="module" -->
<script type="module">
import { greet } from './module.js';
greet();
</script>
<!-- 或者外部文件 -->
<script type="module" src="./main.js"></script>
// package.json
{
"type": "module"
}
// 使用 .mjs 扩展名
// 或者在 package.json 中设置 "type": "module"
import { func } from './module.js';