主要设计思想:
ES6 模块的设计思想是尽量的静态化,使得编译时就能确定模块的依赖关系,以及输入和输出的变量
主要要点
1、使用严格模式(自动采用严格模式)
ES6 模块之中,顶层的this指向undefined,即不应该在顶层代码使用this
2、export、import
模块功能主要由两个命令构成:export和import。export命令用于规定模块的对外接口,import命令用于输入其他模块提供的功能
整体加载: import * as All from 'XXX'
3、export 与 import 的复合写法
export { foo, bar } from 'my_module';
4、 import
引擎处理import语句是在编译时。import和export命令只能在模块的顶层,不能在代码块之中(比如在函数之中)
5、 按需加载\条件加载\动态的模块路径
import()加载模块成功以后,这个模块会作为一个对象,当作then方法的参数
fn(){
return 'B.js'
}
if(a==='加载B模块'){
import(fn()).then(B => {
B.open();
}).catch(error => {
/* Error handling */
})
};
浏览器加载
1、传统加载:<script>标签加载,defer、async实现异步加载
defer:渲染完执行。要等到整个页面在内存中正常渲染结束(DOM 结构完全生成,以及其他脚本执行完成),才会执行;
async:下载完执行。一旦下载完,渲染引擎就会中断渲染,执行这个脚本以后,再继续渲染。
2、加载规则:type="module"。
`<script type="module" src="./B.js" ></script>`
ESM 和 CommonJS 的差异
CommonJS 模块输出的是一个值的拷贝,ES6 模块输出的是值的引用。
CommonJS 模块是运行时加载,ES6 模块是编译时输出接口。
export let counter = 3;
export function incCounter() {
counter++;
}
// main.js
import { counter, incCounter } from './lib';
console.log(counter); // CommonJS输出:3; ESM输出:3
incCounter();
console.log(counter); // CommonJS输出:3;ESM输出:4
循环加载
a依赖b,b依赖c,c又依赖a
1、CommonJS模块的循环加载
CommonJS的做法是,一旦出现某个模块被"循环加载",就只输出已经执行的部分,还未执行的部分不会输出。移交执行权。
a依赖b,b依赖a。
a文件执行到b文件执行到引入时,执行权移交到b文件执行,把文件执行完胜之后再移交给a文件
2、ES6模块的循环加载
ES6模块是动态引用,不存在缓存值的问题,而且模块里面的变量,绑定其所在的模块。
ES6根本不会关心是否发生了"循环加载",只是生成一个指向被加载模块的引用,**需要开发者自己保证**,真正取值的时候能够取到值。(可把变量写成function返回其值,以达到变量提升)