ifeees / articles

“前端晚自修”公众号文章备份
3 stars 0 forks source link

ES6 Module #18

Open rhymecoding opened 6 years ago

rhymecoding commented 6 years ago

ES6 模块两个最主要的特点

相较于CommonJS,ES6 模块有两个最主要的特点。

1.静态加载

ES6 模块的最大特点就是静态加载,也就是在编译时确定模块之间的依赖关系以及导入和导出的接口(变量、函数、类),ES6 模块不能在运行时动态加载

2.ES6 模块不是对象

ES6 模块不是对象,而是通过export导出接口,再通过import导入。顶层的this指向undefined

export & import

1.export

export的作用是导出接口(变量、函数、类)

// 第一种用法:export+声明语句
export let a = 1;

// 第二种用法:export+大括号
let b = 1;
export { // 这里的大括号不是对象
  b
}

// 第三种用法:使用 as 重命名
let c = 1;
export { // 对外输出的是 cx,c 不再可见
  c as cx
}

导出 函数 和 类 的用法也是这样。

不管是export还是import都只能处于模块顶层,如果处于块级作用域内,会报错。

import在编译阶段生成只读引用,执行时,根据这个只读引用,到被加载的模块里面取值。接口与模块内部变量是一一对应关系,export导出的是接口,不能是表达式。

// 错
export 1;

// 错
let a = 1;
export a;

// 错
function b () {
}
export b;

接口与模块内部变量的绑定是动态的

export let a = 1;
setTimeout(() => {
  a = 2;
}, 100); // 100毫秒后 a=2

2.import

import导入接口,大括号中的名称必须和导出的名称相同

// 可以使用 as 重命名,cx 不再可见
import {a, b, cx as cy} from './001';

可以用星号(*)指定一个对象,所有导出的接口都挂载到这个对象

import * as whole from './001';

也可以只执行不导入

import './001';

3.export default

export default指定默认导出接口,后面跟的是一个表达式,不能再是声明语句

let a = 1;
export default a;

// 此时函数是表达式,不是声明
export default function () {}

// 此时类是表达式,不是声明
export default class {}

import可以指定任意名字接收

// 001.mjs
// 一个模块只能有一个默认导出接口,也就是只能使用一次
let a = 1;
export default a;
export let b = 2;

// 002.mjs
// 接收默认导出的变量必须在最前面
import ax, * as x from './001';
console.log(ax, x, x.default); // 1 [Module] { b: 2, default: 1 } 1

根据以上输出,可以看出export default的本质

// export default
export default a;

// 等价于
export {a as default}

// 貌似可以在大括号中用 default 接收,但是因为 default 是关键字,可以用 as 重命名
import ax, {default as ay, b} from './001';
console.log(ax, ay, b); // 1 1 2

export与import的复合写法

// 001.mjs
const a = 1;
export default a;
export const b = 2;

// 002.mjs
// b并没有被导入到当前模块
export {b} from './001';

// 002.mjs
// 导出001.mjs中的默认接口
// 不能这样 export a from './001';
export {default} from './001';

// 002.mjs
// 重命名,此时 b 是默认导出接口,只能有一个默认接口
export {default as ax, b as default} from './001';

// 002.mjs
// 整体导出,不包括001.mjs中的默认接口
// 不能这样 import * as x from './001';
export * from './001';

循环加载

// a.mjs
import {b} from './b';
console.log('a.mjs');
console.log(b);
export let a = 'a';

// b.mjs
import {a} from './a';
console.log('b.mjs');
console.log(a);
export let b = 'b';

执行 a.mjs ,根据多次调试,个人理解的执行过程如下(可能有偏差):

一、编译阶段

编译入口模块

编译阶段结束后,开始进行执行阶段。

二、执行阶段

参考

1.http://es6.ruanyifeng.com/#docs/module 2.http://es6.ruanyifeng.com/#docs/module-loader