ES6对比CommonJs模块
模块 | CommonJs | ES6 |
---|---|---|
适用端 | 服务端 | 服务端 / 浏览器端[主要] |
输出值类型 | 输出值的拷贝 | 输出值的引用 |
加载时机 | 运行时加载 | 编译时加载 |
同步/异步 | require()同步加载 | import异步加载 |
-
加载时机差异
因为CommonJs
加载的是一个对象(Module.exports
导出的内容),该对象只有在脚本运行完毕才会生成;而ES6
模块不是对象,其对外接口是一种静态定义,在静态解析阶段才会完成; -
输出值类型
CommonJs
模块输出的是值得拷贝,一旦输出一个值,模块内部的变化就不会影响到这个值;例如
// 输出模块lib.js
var counter = 3;
function incCounter() {
counter++;
}
module.exports = {
counter: counter,
incCounter: incCounter,
};
// 输入模块main.js
var mod = require('./lib');
console.log(mod.counter); // 3
mod.incCounter();
console.log(mod.counter); // 3
lib.js
模块加载以后,它的内部变化就影响不到输出的mod.counter
了。这是因为mod.counter
是一个原始类型的值,会被缓存。除非写成一个函数,才能得到内部变动后的值。例如:
// lib.js
var counter = 3;
function incCounter() {
counter++;
}
module.exports = {
get counter() {
return counter
},
incCounter: incCounter,
};
// 输出
$ node main.js
3
4
上面代码中,输出的counter
属性实际上是一个取值器函数。现在再执行main.js
,就可以正确读取内部变量counter
的变动了。
而在ES6模块中 :ES6 模块的运行机制与 CommonJS 不一样。JS 引擎对脚本静态分析的时候,遇到模块加载命令import,就会生成一个只读引用。等到脚本真正执行时,再根据这个只读引用,到被加载的那个模块里面去取值。换句话说,ES6 的import有点像 Unix 系统的“符号连接”,原始值变了,import加载的值也会跟着变。因此,ES6 模块是动态引用,并且不会缓存值,模块里面的变量绑定其所在的模块。