ES6 Modules VS CommonJS

关于模块引用

CommonJS输出的是值的拷贝(浅拷贝),A模块引入B模块之后,B模块之后的变化不会影响A模块中的值。而ESM是对一个值的引用(类似于读取的是值的地址),同样以A、B模块为例,A模块中永远使用的是B模块中最新的值。所以ESM是动态引用,不会缓存值。

代码示例ESM

  • 模块A:
    export let a = 1;
    setTimeout(() => { a = 100; }, 500);
    
  • 模块B使用A:
    import { a } from 'A';
    console.log(a); // 1
    setTimeout(() => {
    console.log(a); // 100
    }, 600);
    

修改引用值

  • CommonJS可以修改以及重新赋值(改变指针指向)引用的值。
  • ESM的接口是只读的,不可以修改值(改变指针指向),只存只读,和const类似。

加载方式

  • CommonJS运行时加载,引用的时候先加载整个模块,生成一个对象,然后再从这个生成的对象上读取方法。
  • ESM编译时加载,不是对象,通过export显示的指定输出的代码,import时采用静态命令的形式,加载指定的输出值而不是整个模块。

动态加载

目前来讲ESM还不支持,只能在文件头部import,但是已经在提案中了。而CommonJS则是支持的。

其他

commonJs是会缓存的,会将引入结果缓存再require.cache中,如果不需要缓存可以先删除再引入,如下代码:

export function requireUncached(path: string): any {
  delete require.cache[require.resolve(path)];
  return require(path);
}

参考

https://es6.ruanyifeng.com/#docs/module