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

相关推荐
木易 士心4 小时前
Ref 和 Reactive 响应式原理剖析与代码实现
前端·javascript·vue.js
程序员博博4 小时前
概率与决策 - 模拟程序让你在选择中取胜
前端
被巨款砸中4 小时前
一篇文章讲清Prompt、Agent、MCP、Function Calling
前端·vue.js·人工智能·web
sophie旭4 小时前
一道面试题,开始性能优化之旅(1)-- beforeFetch
前端·性能优化
Cache技术分享4 小时前
204. Java 异常 - Error 类:表示 Java 虚拟机中的严重错误
前端·后端
uhakadotcom4 小时前
execjs有哪些常用的api,如何逆向分析网站的加签机制
前端·javascript·面试
ObjectX前端实验室4 小时前
【图形编辑器架构】:无限画布标尺与网格系统实现解析
前端·canvas·图形学
你的电影很有趣4 小时前
lesson71:Node.js与npm基础全攻略:2025年最新特性与实战指南
前端·npm·node.js
闲蛋小超人笑嘻嘻5 小时前
find数组方法详解||Vue3 + uni-app + Wot Design(wd-picker)使用自定义插槽内容写一个下拉选择器
前端·javascript·uni-app
小牛itbull5 小时前
初始化electron项目运行后报错 electron uninstall 解决方法
前端·javascript·electron