CommonJS 和 ES6 模块引入的区别

CommonJS 和 ES6 模块系统在语法、加载方式和导出机制上的差异

问题

CommonJS 和 ES6 中模块引入有什么区别?

解答

CommonJS

CommonJS 主要用于 Node.js 环境,使用 require 引入模块,module.exports 导出模块。

导出模块:

// moduleA.js
const name = 'John';
module.exports = name;

// 或者导出一个对象
const person = { name: 'John', age: 30 };
module.exports = person;

引入模块:

// main.js
const name = require('./moduleA');
console.log(name); // 'John'

const person = require('./moduleA');
console.log(person.name); // 'John'

特点:

  1. 动态引入require 可以在函数体内、条件语句中使用
if (condition) {
    const moduleA = require('./moduleA');
}
  1. 同步加载:模块在执行 require 时立即加载并返回结果

  2. 导出值的拷贝:对于引用类型,修改属性会在所有引用中反映

const obj = require('./moduleA');
obj.newProp = 'new';
console.log(require('./moduleA').newProp); // 'new'

ES6 模块

ES6 模块是 ECMAScript 标准的一部分,使用 importexport 语法。

导出模块:

// moduleA.js
export const name = 'John';

// 导出默认值
const person = { name: 'John', age: 30 };
export default person;

引入模块:

// main.js
import { name } from './moduleA';
console.log(name); // 'John'

// 引入默认导出
import person from './moduleA';
console.log(person.name); // 'John'

特点:

  1. 静态引入import 必须在文件顶部声明,不能在函数体或条件语句中使用
// 错误的用法
if (condition) {
    import { name } from './moduleA'; // 报错
}
  1. 异步加载:浏览器中的 ES6 模块是异步加载的,不会阻塞页面

  2. 导出值的引用:导出模块中的值变化时,所有引用都会同步更新

// moduleA.js
export let count = 1;
setTimeout(() => { count += 1; }, 1000);

// main.js
import { count } from './moduleA';
setTimeout(() => { console.log(count); }, 2000); // 2

兼容性

在 Node.js 环境中,可以使用 Babel 或 Webpack 将 ES6 模块转换为 CommonJS 模块。现代构建工具支持同时使用两种模块系统,并在构建时根据目标环境转换。

关键点

  • 语法:CommonJS 使用 require/module.exports,ES6 使用 import/export
  • 加载方式:CommonJS 是同步加载,ES6 是静态分析和异步加载
  • 导出机制:CommonJS 导出值的拷贝,ES6 导出值的引用
  • 使用场景:CommonJS 主要用于 Node.js,ES6 模块是标准规范,适合现代前端开发
  • 动态性:CommonJS 支持动态引入,ES6 模块必须静态声明