文章目录

JavaScript 模块导入:CommonJS 与 ES6 模块

发布于 2026-04-03 03:59:14 · 浏览 6 次 · 评论 0 条

JavaScript 模块导入:CommonJS 与 ES6 模块

JavaScript 的模块系统用于将代码拆分成独立、可复用的文件。主流有两种规范:CommonJS(主要用于 Node.js)和 ES6 模块(现代浏览器和新版 Node.js 支持)。它们在语法、加载方式和使用场景上有本质区别。


区分两种模块的核心差异

特性 CommonJS ES6 模块
加载时机 运行时加载 编译时加载(静态分析)
导出方式 module.exportsexports export
导入方式 require() import
是否支持异步导入 否(同步) 是(支持 import() 动态导入)
默认是否严格模式
能否在浏览器直接使用 否(需打包工具) 是(需 <script type="module">

在 Node.js 中使用 CommonJS

Node.js 默认使用 CommonJS 规范。按以下步骤操作:

  1. 创建一个名为 math.js 的文件,写入导出逻辑:
    
    // math.js
    function add(a, b) {
    return a + b;
    }

function multiply(a, b) {
return a * b;
}

// 导出多个函数
module.exports = {
add,
multiply
};


2. **创建**另一个文件 `app.js`,**导入并使用**上面的模块:
```javascript
// app.js
const math = require('./math');

console.log(math.add(2, 3));      // 输出 5
console.log(math.multiply(4, 5)); // 输出 20
  1. 运行命令:
    node app.js

注意:require() 的路径必须包含 ./../ 表示相对路径,否则 Node.js 会去 node_modules 查找。


在浏览器或现代环境中使用 ES6 模块

ES6 模块是 JavaScript 官方标准,适用于现代浏览器和启用 ES 模块的 Node.js 环境。

在浏览器中使用

  1. 创建 utils.js 文件:
    
    // utils.js
    export function formatDate(date) {
    return date.toISOString().split('T')[0];
    }

export const PI = 3.14159;


2. **创建** HTML 文件,**引入**模块:
```html
<!-- index.html -->
<!DOCTYPE html>
<html>
<head>
  <title>ES6 Module Demo</title>
</head>
<body>
  <script type="module">
    import { formatDate, PI } from './utils.js';

    console.log(formatDate(new Date())); // 如 "2024-06-15"
    console.log(PI); // 3.14159
  </script>
</body>
</html>
  1. 通过 HTTP 服务器打开该 HTML 文件(不能直接双击本地文件,因浏览器禁止 file:// 协议加载模块)。可使用以下任一命令启动简易服务器:
    
    # 如果安装了 Python 3
    python -m http.server 8000

或使用 Node.js 的 http-server(需先 npm install -g http-server)

http-server


### 在 Node.js 中启用 ES6 模块

默认 `.js` 文件被视为 CommonJS。要使用 ES6 模块,有两种方式:

#### 方式一:文件扩展名为 `.mjs`
1. **重命名**文件为 `app.mjs`
2. **写入** ES6 模块代码:
```javascript
// app.mjs
import { PI } from './constants.js';
console.log(PI);
  1. 运行
    node app.mjs

方式二:在 package.json 中声明类型

  1. 在项目根目录创建或修改 package.json添加字段:
    {
    "type": "module"
    }
  2. 此时所有 .js 文件默认为 ES6 模块,可直接使用 import/export
    // main.js
    import { greet } from './greet.js';
    greet();

导入导出的详细语法对照

CommonJS 导出方式

  • 导出整个对象

    module.exports = { name: 'Alice', age: 30 };
  • 逐个添加属性(等价于上例):

    exports.name = 'Alice';
    exports.age = 30;
  • 导出单个值(如类或函数)

    module.exports = class User {
    constructor(name) {
      this.name = name;
    }
    };

CommonJS 导入方式

  • 导入整个模块

    const userModule = require('./user');
  • 解构导入(仅适用于导出为对象的情况):

    const { name, age } = require('./user');

ES6 模块导出方式

  • 命名导出(可多个):

    export const API_URL = 'https://api.example.com';
    export function fetchUser(id) { /* ... */ }
  • 默认导出(每个文件只能有一个):

    export default class ApiService { /* ... */ }
  • 混合导出

    
    const version = '1.0';
    function init() { /* ... */ }

export { version, init };
export default function runApp() { / ... / }


### ES6 模块导入方式

- **导入命名导出**:
```javascript
import { API_URL, fetchUser } from './api';
  • 导入默认导出

    import ApiService from './api';
  • 同时导入默认和命名导出

    import ApiService, { version, init } from './api';
  • 重命名导入

    import { fetchUser as getUser } from './api';
  • 导入整个模块为命名空间

    import * as api from './api';
    console.log(api.API_URL);
    api.fetchUser(123);
  • 动态导入(异步)

    async function loadModule() {
    const module = await import('./heavy-module.js');
    module.doSomething();
    }

常见错误与避坑指南

  1. 在 CommonJS 中错误使用 import
    Node.js 默认不识别 import,除非启用了 ES 模块。若报错 SyntaxError: Cannot use import statement outside a module,请检查:

    • 文件是否为 .mjs
    • package.json 是否有 "type": "module"
    • 是否在浏览器中忘了加 type="module"
  2. 在 ES6 模块中使用 require
    ES6 模块环境下无法使用 require。若需兼容,可改用动态 import()

  3. 路径省略扩展名问题

    • CommonJS:require('./lib') 会自动尝试 lib.jslib.jsonlib.node
    • ES6 模块:必须显式写出扩展名(如 import './lib.js'),否则浏览器或 Node.js 会报错
  4. 循环依赖处理不同

    • CommonJS:返回已执行部分的对象(可能未初始化完成)
    • ES6 模块:绑定是“活引用”,但需注意初始化顺序
  5. 顶层 this 的值不同

    • CommonJS:this 指向 module.exports
    • ES6 模块:thisundefined

互操作:在同一个项目中混合使用

Node.js 允许在 ES6 模块中导入 CommonJS 模块,反之亦然(有限支持)。

ES6 模块导入 CommonJS 模块

假设 cjs-lib.js 是 CommonJS:

// cjs-lib.js
module.exports = { value: 42 };

在 ES6 模块中导入:

// esm-consumer.js
import cjs from './cjs-lib.js'; // 整个 module.exports 作为默认导出
console.log(cjs.value); // 42

// 或使用命名导入(Node.js 会将 CommonJS 的属性提升为命名导出)
import { value } from './cjs-lib.js';
console.log(value); // 42

CommonJS 导入 ES6 模块

需使用动态 import()(因为 CommonJS 是同步的,而 ES6 模块是静态的):

// cjs-consumer.js
async function useESM() {
  const esm = await import('./esm-lib.js');
  esm.default(); // 调用默认导出
}

注意:Node.js 对这种互操作的支持仍在演进,建议尽量统一模块系统。


选择建议:新项目优先使用 ES6 模块(.js + "type": "module"),因其是标准、支持静态分析、兼容未来生态。遗留项目或重度依赖 npm 包(多为 CommonJS)可继续使用 CommonJS,或通过构建工具(如 Webpack、Vite)统一处理。

评论 (0)

暂无评论,快来抢沙发吧!

扫一扫,手机查看

扫描上方二维码,在手机上查看本文