CommonJS与ES6区别
- 1、ES6模块输出的是值的引用,而CommonJS模块输出的是值的拷贝
- 2、ES6模块是在编译时执行,而CommonJS模块是在运行时加载
CommonJS模块输出值的拷贝
// a.js
var b = require('./b');
console.log(b.foo);
setTimeout(() => {
console.log(b.foo);
console.log(require('./b').foo);
}, 1000);
// b.js
let foo = 1;
console.log('b.js')
setTimeout(() => {
foo = 2;
}, 500);
module.exports = {
foo: foo,
};
//b.js
//1
//1
//1
b 模块加载以后,它的内部 foo 变化就影响不到输出的 exports.foo 了。这是因为 foo 是一个原始类型的值,会被缓存。所以如果你想要在 CommonJS 中动态获取模块中的值,那么就需要借助于函数延时执行的特性。
// b.js
let foo = 1;
setTimeout(() => {
foo = 2;
}, 500);
module.exports = {
foo: () => { //返回一个方法
return foo;
},
};
总结:
- 1、CommonJS 模块重复引入的模块并不会重复执行,再次获取模块直接获得暴露的 module.exports 对象
- 2、如果你要处处获取到模块内的最新值的话,也可以你每次更新数据的时候每次都要去更新 module.exports 上的值
- 3、如果你暴露的 module.exports 的属性是个对象,那就不存在这个问题了
ES6模块输出引用
执行node --experimental-modules a.mjs
//a.mjs
import {foo} from './b';
console.log(foo);
setTimeout(() => {
console.log(foo);
import('./b').then(({foo})=>{
console.log(foo);
});
}, 1000);
// b.mjs
console.log('b.js')
setTimeout(() => {
foo = 2;
}, 500);
export let foo = 1;
//b.js
//1
//2
//2
在 ES6 模块中就不再是生成输出对象的拷贝,而是动态关联模块中的值
ES6静态编译
ES6 模块编译时执行会导致有以下两个特点:
- 1、import 命令会被 JavaScript 引擎静态分析,优先于模块内的其他内容执行
- 2、export 命令会有变量声明提前的效果
import 优先执行:
//a.mjs
console.log('a.mjs');
import { foo } from './module2';
// b.mjs
export let foo = 1;
console.log('b.mjs');
//b.mjs
//a.mjs
虽然 a 模块中 import 引入晚于 console.log('a.mjs'),但是它被 JS 引擎通过静态分析,提到模块执行的最前面,优于模块中的其他部分的执行。由于 import 是静态执行,所以 import 具有提升效果即 import 命令在模块中的位置并不影响程序的输出。
export 变量声明提升:
//a.mjs
console.log('a.mjs');
import { foo } from './module2';
export const bar = 1;
export const bar2 = () => {
console.log('bar2');
}
export function bar3() {
console.log('bar3');
}
// b.mjs
export let foo = 1;
import * as a from './module';
console.log(a);
[Module] {
bar: <uninitialized>,
bar2: <uninitialized>,
bar3: [Function: bar3] }
a.mjs
a 模块引用了 b 模块,b 模块也引用了 a 模块,export 声明的变量也是优于模块其它内容的执行的,但是具体对变量赋值需要等到执行到相应代码的时候。
动态 import()
import() 主要是为了解决 ES6 模块无法在运行时确定模块的引用关系,所以需要引入 import()