ES6模块与Commonjs模块对比

模块化语法区分

Posted by Cycle263 on February 3, 2019

ES6模块与Commonjs模块对比

模块化规范:即为 JavaScript 提供一种模块编写、模块依赖和模块运行的方案。

  • require vs import

    require/exports import/export
    2010年前后诞生 2015年的ES2015版本
    野生规范 名门正派
    CommonJS、AMD、CMD ECMAScript 6
    动态加载,程序运行的时候去解析加载 静态加载,编译的时候去做解析请求包
  • ES6模块与CommonJS模块的差异

    ES 6 module CommonJs Module
    值的引用 值的拷贝(浅拷贝))
    编译时加载(编译时确定依赖,输入和输出) 运行时加载(运行时确定依赖,输入和输出)
    原始值变化,import加载的值也会跟着变化 基本类型不会跟着变化,可以手动每次更新module.exports的值
    有default默认导出对象 没有
    动态绑定,不缓存 会缓存执行代码的结果,导致引用代码块的值不会随着包代码的值变化而变化
    静态分析,加载效率高 无法静态分析,效率偏低
    // even.js
    import { odd } from './odd'
    export var counter = 0;
    export function even(n) {
      counter++;
      return n == 0 || odd(n - 1);
    }
    
    // odd.js
    import { even } from './even';
    export function odd(n) {
      return n != 0 && even(n - 1);
    }
    

    CommonJs 模块输出的是一个值的拷贝,ES6模块输出的是一个值的引用; CommonJS 模块是运行时加载,也就是遇到require就加载并执行,ES6模块是编译时输出接口,ES6输入的模块变量,只是一个符号链接(一个引用),所以这个变量是只读的,对它进行重新赋值就会报错。也就是说,ES6模块是动态引用,不存在缓存值的问题,而且模块里面的变量,绑定其所在的模块,每次都会动态地去被加载的模块取值。

    模块加载AMD,CMD,CommonJS Modules/2.0 规范这些规范的目的都是为了 JavaScript 的模块化开发,特别是在浏览器端的对于依赖的模块,AMD 是提前执行,CMD 是延迟执行CMD 推崇依赖就近,AMD 推崇依赖前置。

    // a.js
    export let a = 10;
    export let b = 10;
    export function add() {
      a = 15;
      b = 20;
      return a+b;
    };
    
    // b.js
    import {a, b, add} from './a.js';
    a+b;    // 20
    add();  // 35
    a+b;    // 35, 导出的变量是只读引用
    
  • Commonjs模块的加载原理

    CommonJS的一个模块,就是一个脚本文件。require命令第一次加载该脚本,就会执行整个脚本,然后在内存生成一个对象,类似于{id:'', exports: {}, loaded: true},其中ID表示模块名,exports是模块输出的各个接口,loaded表示模块脚本是否执行完。

    以后需要用到这个模块的时候,就会到exports属性上面取值。即使再次执行require命令,也不会再次执行该模块,而是到缓存之中取值。

  • Commonjs模块的循环引用

    不会再次执行该模块,而是到缓存之中取值。