关于ESM(es6 module)学习

647 阅读2分钟

主要设计思想:

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返回其值,以达到变量提升)