ES6 Module 深入学习

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 开发至关重要,它不仅能提高代码质量,还能优化应用性能。

相关推荐
前端AK君5 小时前
Gitlab 线上合并冲突的坑
前端
章丸丸5 小时前
Tube - Studio Videos
前端·后端
因吹斯汀6 小时前
一饭封神:当AI厨神遇上你的冰箱,八大菜系大师在线battle!
前端·vue.js·ai编程
再学一点就睡6 小时前
NATAPP 内网穿透指南:让本地项目轻松 “走出去”
前端
拜无忧6 小时前
2025最新React项目架构指南:从零到一,为前端小白打造
前端·react.js·typescript
稻草人不怕疼6 小时前
记一次从“按钮点不动”到“窗口派发缺失”的排查过程
前端
irving同学462386 小时前
TypeORM 列装饰器完整总结
前端·后端·nestjs
彭于晏爱编程6 小时前
你真的了解 Map、Set 嘛
前端
崔璨7 小时前
详解Vue3的响应式系统
前端·vue.js