为什么需要module模块?
历史上,JavaScript 一直没有模块(module)体系,无法将一个大程序拆分成互相依赖的小文件,再用简单的方法拼装起来。
在 ES6 之前,社区制定了一些模块加载方案,最主要的有 CommonJS 和 AMD 两种。前者用于服务器,后者用于浏览器。
ES6 在语言标准的层面上,实现了模块功能,而且实现得相当简单,完全可以取代 CommonJS 和 AMD 规范,成为浏览器和服务器通用的模块解决方案。
ES6 模块的设计思想
ES6 模块的设计思想是尽量的静态化,使得编译时就能确定模块的依赖关系,以及输入和输出的变量。CommonJS 和 AMD 模块,都只能在运行时确定这些东西。由于 ES6 模块是编译时加载,使得静态分析成为可能。
命令
ES6 模块不是对象,而是通过export,import命令输出输入。
export命令用于规定模块的对外接口,import命令用于输入其他模块提供的功能。
一个模块就是一个独立的文件。该文件内部的所有变量,外部无法获取。如果你希望外部能够读取模块内部的某个变量,就必须使用export关键字输出该变量。
具名接口
var firstName = 'Michael';
var lastName = 'Jackson';
function v1() { ... }
export { firstName as 别名, lastName, v1 }; //建议这种
import { firstName as 别名, lastName, v1 } from './export.js';
function setName(element) {
element.textContent = firstName + ' ' + lastName;
}
v1()
import命令输入的变量都是只读的,因为它的本质是输入接口。也就是说,不允许在加载模块的脚本里面,改写接口。
import命令具有提升效果,会提升到整个模块的头部,首先执行。
整体加载
import * as circle from './circle';
模块整体加载所在的那个对象(上例是circle),应该是可以静态分析的,所以不允许运行时改变。下面的写法都是不允许的。
这是不对的:// circle.foo = 'hello';
默认接口 export default
默认输出
export default function(){} //index
import customIndex from './index';
customIndex()
export default命令用于指定模块的默认输出。显然,一个模块只能有一个默认输出,因此export default命令只能使用一次。
// 正确 export let a = 1;
// 正确 let a = 1; export default a
// 错误 export default let a = 1;export default a的含义是将变量a的值赋给变量default。所以会报错。
import()
ES2020提案。
引擎处理import语句是在编译时,也导致无法在运行时加载模块。在语法上,条件加载就不可能实现。
import()函数,支持动态加载模块。返回一个Promise对象。
import()函数可以用在任何地方,不仅仅是模块,非模块的脚本也可以使用。
import()类似于 Node.js 的require()方法,区别主要是前者是异步加载,后者是同步加载。
适合场景:
- 按需加载
- 条件加载
if(A) {import('A').then(---)}else{---}
- 动态的模块路径
import(f()).then(----)