动态与静态

CommonJS与ES6 Module最本质的区别在于CommonJS对模块依赖的解决是“动态的”而ES6 Module是“静态的”。在这里“动态的”含义是,模块依赖关系的建立发生在代码运行阶段;而“静态”则是模块依赖关系的建立发生在代码编译阶段
接下来举例说明一下

commonJS例子

B文件
//calculator.js
module.exports={name:"calculator"};

A文件
//index.js
const name=require('./calculator.js').name;

当模块A加载模块B时,会执行B中的代码,并将其module.exports对象作为require函数的返回值进行返回。并且require的模块路径可以动态指定,并支持传入一个表达式或者一个if进行判断是否加载模块。因此可以看出,在commonJS模块被执行前,并没有办法确定明确的依赖关系,模块的导入、导出发生在代码的运行阶段。

ES6 Module例子

//calculator.js
export const name='calculator';

//index.js
import {name} from './calculator.js';

ES6 Module的导入、导出语句都是声明式的,它不支持导入的路径是一个表达式,并且导入、导出语句必须位于模块的顶层作用域不能放到if语句中。因此ES6 Module是一个静态模块结构。

ES6 Module相比与CommonJS的优点

① 死代码检测和排除。我们可以用静态分析工具检测出哪些模块没有被调用过。
② 模块变量类型检查。
③ 编译器优化。ES6 Module支持直接导入变量,减少了引用层级,程序效率更高

值拷贝与动态映射

在导入一个模块的时候,对于CommonJS来说获取的是一份导出值的拷贝;而ES6 Module则是值的动态映射,并且这个映射是可读的。

CommonJS值拷贝例子

//calculator.js
var count=0;
module.exports={
  count:count,
  ADD:function (a,b) {
      count+=1;
      return a+b;
  }
};


//inde.js
var count=require('./calculator').count;
var add=require('./calculator').ADD;

console.log(count);
add(2,3);
console.log(count);

count +=1;
console.log(count);

运行结果

commonjs 使用ESM_ES6


index.js中的count是对calculator.js中的count的一份拷贝,因此在调用ADD函数的时候,虽然改变了calculator.js中的count的值,但是并不会对index.js中导入时创建的副本造成影响。也就是说你在index.js中只要不是通过ADD函数对count的操作,都不会影响到calculator.js中的count。而是影响了副本的count

ES6 Module动态映射例子

//calculator.js
var count=0;
const ADD=function(a,b){
      count+=1;
      return a+b;
};
export {count,ADD}


//inde.html
<script type="module">
 import {count,ADD} from './src/calculator.js';
 console.log(count);
 ADD(2,3);
 console.log(count);
</script>

运行结果

commonjs 使用ESM_webpack_02


可以发现导入的变量其实是对原有值的动态映射。index.html中的count是对calculator.js中count值的实时反映,当我们调用ADD函数更改了calculator.js中count值时,index.html中的count的值也会随之变化。