ES6 Module 深入学习
ES6 模块系统是 JavaScript 语言层面的模块化解决方案,提供了更现代化、更强大的模块功能。让我们深入探索其核心概念和高级用法。
注意事项
- ES6 模块的导入变量是只读的引用
1. 基本语法
导出 (Export)
javascript
// 命名导出 (每个模块多个)
export const name = 'value';
export function myFunction() { /* ... */ }
export class MyClass { /* ... */ }
// 或者统一导出
const a = 1;
const b = 2;
export { a, b };
// 重命名导出
export { a as renamedA };
导入 (Import)
javascript
// 导入命名导出
import { a, b } from './module.js';
// 重命名导入
import { a as importedA } from './module.js';
// 导入所有命名导出作为对象
import * as module from './module.js';
// 导入默认导出
import defaultExport from './module.js';
// 混合导入
import defaultExport, { namedExport } from './module.js';
2. 默认导出 vs 命名导出
默认导出 (每个模块一个)
javascript
// 导出
const mainFunction = () => { /* ... */ };
export default mainFunction;
// 或者直接导出
export default function() { /* ... */ };
// 导入
import mainFunction from './module.js';
命名导出 (推荐用于工具函数库)
javascript
// utils.js
export const formatDate = (date) => { /* ... */ };
export const validateEmail = (email) => { /* ... */ };
export const debounce = (fn, delay) => { /* ... */ };
// 使用
import { formatDate, debounce } from './utils.js';
3. 动态导入 (Dynamic Import)
javascript
// 按需加载模块
const loadModule = async () => {
try {
const module = await import('./module.js');
module.doSomething();
} catch (error) {
console.error('模块加载失败:', error);
}
};
// 条件导入
if (someCondition) {
const { feature } = await import('./feature.js');
feature();
}
// 动态路径
const moduleName = getUserPreference();
const userModule = await import(`./modules/${moduleName}.js`);
4. 重新导出 (Re-exporting)
javascript
// 统一入口文件 (index.js 或 barrel file)
export { Button } from './components/Button.js';
export { Input } from './components/Input.js';
export { Modal } from './components/Modal.js';
// 重命名重新导出
export { default as ThemeProvider } from './theme/Provider.js';
// 聚合所有导出
export * from './utils/helpers.js';
export * from './utils/validators.js';
// 注意:export * 不会包含默认导出
5. 循环依赖处理
ES6 模块处理循环依赖的方式:
javascript
// a.js
import { b } from './b.js';
export let a = 'a';
export function getB() {
return b;
}
// b.js
import { a, getB } from './a.js';
export let b = 'b';
console.log(a); // 由于变量提升,这里可能是 undefined
// 解决方案:使用函数封装
export function getA() {
return a; // 使用时a已经初始化
}
6. 模块的实时绑定 (Live Bindings)
javascript
// counter.js
export let count = 0;
export function increment() {
count++;
}
// main.js
import { count, increment } from './counter.js';
console.log(count); // 0
increment();
console.log(count); // 1 - 值被更新了
// 注意:不能直接修改导入的变量,ES6 模块的导入变量是只读的引用(read-only view),而不是值的拷贝。
// count = 5; // 错误:Assignment to constant variable
7. 使用建议和最佳实践
文件组织
text
src/
components/
Button/
index.js // 重新导出
Button.js
styles.css
utils/
index.js // 工具函数聚合
helpers.js
validators.js
constants/
index.js // 常量定义
代码示例
javascript
// constants/index.js
export const API_URL = process.env.API_URL;
export const MAX_ITEMS = 100;
export const DEFAULT_TIMEOUT = 5000;
// utils/helpers.js
export const formatCurrency = (amount, currency = 'USD') => {
return new Intl.NumberFormat('en-US', {
style: 'currency',
currency
}).format(amount);
};
export const generateId = () => {
return Math.random().toString(36).substr(2, 9);
};
// components/Button/index.js
export { default } from './Button';
export { default as ButtonGroup } from './ButtonGroup';
// 使用
import Button, { ButtonGroup } from './components/Button';
import { formatCurrency, generateId } from './utils';
import { API_URL, MAX_ITEMS } from './constants';
8. 与 CommonJS 的互操作
在 ES6 模块中导入 CommonJS
javascript
// 导入整个模块
import cjsModule from './commonjs-module.cjs';
// 注意:CommonJS 模块的命名导出需要特殊处理
import { namedExport } from './commonjs-module.cjs'; // 可能不工作
// 更好的方式
import cjsModule from './commonjs-module.cjs';
const { namedExport } = cjsModule;
在 Node.js 中的使用
json
// package.json
{
"type": "module", // 使用 ES6 模块
"exports": {
".": {
"import": "./dist/esm/index.js", // ES6 版本
"require": "./dist/cjs/index.js" // CommonJS 版本
}
}
}
9. 高级模式
模块工厂模式
javascript
// createLogger.js
export const createLogger = (prefix = '') => {
return {
log: (...args) => console.log(prefix, ...args),
error: (...args) => console.error(prefix, ...args)
};
};
// 使用
import { createLogger } from './createLogger.js';
const logger = createLogger('[App]');
logger.log('Message');
插件系统
javascript
// pluginSystem.js
const plugins = new Set();
export const registerPlugin = (plugin) => {
plugins.add(plugin);
};
export const initializePlugins = async (context) => {
for (const plugin of plugins) {
await plugin.initialize(context);
}
};
// 动态加载插件
export const loadPlugin = async (pluginPath) => {
const plugin = await import(pluginPath);
registerPlugin(plugin.default);
};
总结
ES6 模块系统提供了:
- ✅ 静态分析能力
- ✅ 更好的 tree shaking
- ✅ 实时绑定机制
- ✅ 原生的浏览器支持
- ✅ 清晰的语法结构
掌握 ES6 模块系统对于现代 JavaScript 开发至关重要,它不仅能提高代码质量,还能优化应用性能。