三十的博客

JavaScript 模块化入门:从零理解 ES6 模块系统

本文内容基于 AI 生成结果整理,可能包含不准确信息,仅供参考使用。
发布时间
阅读量 加载中...

一、模块化是什么?为什么重要?

想象你在组装一台电脑:

代码模块化也是同样道理,它带来三大核心优势:

二、ES6 模块基础语法

1. 导出模块:三种方式

javascript
// utils.js

// 1. 单独导出(推荐)
export const PI = 3.1415926;
export function double(x) {
  return x * 2;
}

// 2. 集中导出
const VERSION = "1.0";
function log(message) {
  console.log(message);
}
export { VERSION, log };

// 3. 默认导出(每个文件只能有一个)
export default class Calculator {
  add(a, b) {
    return a + b;
  }
}

2. 导入模块:四种方式

javascript
// app.js

// 1. 导入命名导出
import { PI, double } from "./utils.js";
console.log(PI); // 3.1415926

// 2. 导入默认导出
import Calculator from "./utils.js";
const calc = new Calculator();

// 3. 重命名导入
import { log as logger } from "./utils.js";

// 4. 整体导入
import * as utils from "./utils.js";
console.log(utils.VERSION);

三、实战应用场景

场景 1:组件化开发

javascript
// components/Button.js
export default function Button(text) {
  const button = document.createElement("button");
  button.textContent = text;
  return button;
}

// main.js
import Button from "./components/Button.js";
document.body.appendChild(Button("点击我"));

场景 2:工具库封装

javascript
// lib/math.js
export function sum(...numbers) {
  return numbers.reduce((total, num) => total + num, 0);
}

export function average(...numbers) {
  return sum(...numbers) / numbers.length;
}

// app.js
import { sum, average } from "./lib/math.js";
console.log(sum(1, 2, 3)); // 6

四、常见问题解答

Q1:什么时候用默认导出?

最佳实践 ​:

javascript
// 默认导出
export default function() { ... }

// 导入时可以任意命名
import myFunction from './module.js'

Q2:循环依赖怎么办?

解决方案 ​:

重构代码结构,避免循环 使用函数提升特性

javascript
// a.js
import { b } from "./b.js";
export function a() {
  return b();
}

// b.js
import { a } from "./a.js";
export function b() {
  return a();
} // ❌ 避免这样设计

Q3:浏览器兼容性如何处理?

两种方案 ​:

使用打包工具(Webpack/Rollup) 动态导入 + 回退方案

javascript
<script type="module" src="app.js"></script>
<script nomodule src="legacy.js"></script>

五、进阶技巧

1. 动态导入(按需加载)

javascript
// 点击按钮时才加载模块
button.addEventListener("click", async () => {
  const module = await import("./dialog.js");
  module.showDialog("Hello!");
});

2. 复合导出模式

javascript
// 先集中导入再重新导出
export { default as Button } from "./Button.js";
export { Input, Textarea } from "./formElements.js";

3. 配合打包工具优化

javascript
// webpack.config.js
module.exports = {
  optimization: {
    splitChunks: {
      chunks: "all", // 自动拆分公共模块
    },
  },
};

六、模块化最佳实践

javascript
/**
 * 计算商品折扣价格
 * @param {number} price - 原价
 * @param {number} discount - 折扣比例(0-1)
 * @returns {number} 折后价格
 */
export function applyDiscount(price, discount) {
  return price * (1 - discount);
}

七、从零实现简易模块加载器

理解模块原理(教学示例):

javascript
const moduleCache = {};

function require(moduleName) {
  if (moduleCache[moduleName]) {
    return moduleCache[moduleName].exports;
  }

  const module = {
    exports: {},
  };

  // 实际实现中这里会读取文件内容
  const code = `
        const message = "Hello Module"
        module.exports = { message }
    `;

  // 相当于eval但更安全
  Function("module", "exports", code)(module, module.exports);

  moduleCache[moduleName] = module;
  return module.exports;
}

const myModule = require("example");
console.log(myModule.message); // "Hello Module"
#Es6 #Javascript