ES6的模块化和commonJS的模块化有什么区别?

304 阅读4分钟

ES6模块化(ES Modules)和CommonJS模块化是两种在JavaScript中实现模块化的方式,它们的核心区别在于模块加载、导出方式、执行时机、以及与同步/异步操作的关系等方面。以下是它们的主要区别:

1学习.png

1. 语法差异

ES6模块化(ES Modules)

  • 导出: ES6 模块使用 exportexport default 关键字来导出模块。

    // 命名导出
    export const name = 'John';
    export function greet() {
      console.log('Hello, ' + name);
    }
    
    // 默认导出
    export default function() {
      console.log('This is the default export');
    }
    
  • 导入: 使用 import 来引入模块。

    import { name, greet } from './module';
    import defaultFunction from './module';
    

CommonJS模块化

  • 导出: CommonJS 使用 module.exportsexports 来导出模块。

    // 导出一个对象
    module.exports = {
      name: 'John',
      greet: function() {
        console.log('Hello, ' + this.name);
      }
    };
    
    // 或者导出一个单一值
    module.exports = function() {
      console.log('This is a function');
    };
    
  • 导入: 使用 require() 来引入模块。

    const module = require('./module');
    module.greet();
    

2. 模块加载机制

ES6模块化

  • 静态加载:ES6 模块是静态分析的,模块的依赖关系在编译时就已经确定。模块的导入和导出是事先定义好的,不会在运行时动态改变。

  • 按需加载:ES6 模块支持懒加载(import()),可以异步加载模块,而不仅限于同步加载。默认情况下,ES6 模块会在代码运行时以同步的方式加载,但是可以通过 import() 实现按需加载,适用于代码分割(如Webpack中常见的懒加载)。

    // 动态导入模块
    import('./module').then(module => {
      module.greet();
    });
    

CommonJS模块化

  • 动态加载:CommonJS 模块是动态加载的,模块的导入和导出是在代码执行时解析的,require() 会在运行时解析模块。
  • 同步加载:CommonJS 模块加载是同步的,意味着当你调用 require() 加载一个模块时,代码会在加载完成之前暂停执行。因此,CommonJS 不适合在浏览器环境中直接使用,因为它假设文件是本地的并且可以同步访问。

3. 执行时机

ES6模块化

  • 模块是延迟执行的:在ES6模块中,模块会在被导入时立即执行,而且 ES6 模块是按需加载的,即只有在使用模块时,模块的代码才会执行。
  • 严格模式:所有 ES6 模块都在严格模式下执行,因此 this 在模块代码中始终是 undefined

CommonJS模块化

  • 模块立即执行:CommonJS 模块在第一次被 require 时会立即执行,并缓存结果。即使同一个模块被多次 require,它的内容只会执行一次,之后的调用都返回缓存的模块。

    // a.js
    module.exports = function() {
      console.log('Module a executed');
    };
    
    // main.js
    const a = require('./a'); // 执行 a.js
    const b = require('./a'); // 不会再次执行 a.js,而是使用缓存的模块
    

image.png

4. 模块缓存

ES6模块化

  • 没有缓存机制:由于 ES6 模块是静态的,模块的导入一旦完成,就可以直接使用它的导出内容。每个导入的模块都会维持一个引用,而不是缓存模块本身。

CommonJS模块化

  • 模块缓存:CommonJS 会缓存每个模块的 exports,这意味着在第一次 require 时,模块会被加载并执行,之后的 require 调用会返回缓存的结果。

5. 支持环境

ES6模块化

  • 浏览器支持:ES6 模块原生支持浏览器(尽管旧版本的浏览器不支持,但现代浏览器已经支持)。
  • Node.js支持:Node.js 从 v12 开始原生支持 ES6 模块,但要注意,需要将文件的扩展名改为 .mjs,或者在 package.json 中指定 "type": "module" 来启用。

CommonJS模块化

  • Node.js支持:CommonJS 是 Node.js 的原生模块化系统。默认情况下,Node.js 中的 JavaScript 文件使用 CommonJS 模块规范。
  • 浏览器支持:CommonJS 本身并不直接支持浏览器,通常需要通过工具如 Webpack 或 Browserify 来将 CommonJS 模块转换为浏览器可用的格式。

6. 兼容性

  • ES6模块和CommonJS互相兼容:在Node.js中,你可以同时使用 ES6 模块和 CommonJS 模块,但需要注意一些细节。例如,在 CommonJS 中引入 ES6 模块时,你需要使用 import,而在 ES6 模块中引入 CommonJS 模块时,require() 依然有效。

    ES6导入 CommonJS:

    import myModule from './commonjs-module'; // 可能需要 `.default` 来获取默认导出的内容
    

    CommonJS导入 ES6模块:

    const myModule = require('./es6-module').default;
    

总结:

  • ES6模块 更适合于现代JavaScript开发,具有静态分析、支持异步加载、模块化和更清晰的语法。
  • CommonJS模块 主要用于Node.js环境,特点是同步加载、动态模块解析,适用于服务器端开发,但不太适合浏览器环境,除非通过打包工具进行转换。

两者各有优缺点,通常在浏览器环境中使用 ES6 模块,在Node.js中则更常用 CommonJS,但在现代应用中,尤其是配合构建工具(如 Webpack、Babel)时,ES6 模块正逐渐成为标准。

dacd2633d04544dabaac13d20e4eb0ef~tplv-73owjymdk6-jj-mark-v1_0_0_0_0_5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5LiN54ix6K-06K-d6YOt5b6357qy_q75.webp