1. 认识 ES Module
- JavaScript没有模块化一直是它的痛点,所以才会产生我们前面学习的社区规范:CommonJS、AMD、CMD等,所以在 ECMA推出自己的模块化系统时,大家也是兴奋异常。
- ES Module和CommonJS的模块化有一些不同之处:
- 一方面它使用了import和export关键字;
- 另一方面它采用编译期的静态分析,并且也加入了动态引用的方式;
- ES Module模块采用export和import关键字来实现模块化:
export负责将模块内的内容导出;import负责从其他模块导入内容;
- 了解:采用ES Module将自动采用严格模式:use strict
2. export关键字
- export关键字将一个模块中的变量、函数、类等导出;
- 我们希望将其他中内容全部导出,它可以有如下的方式:
- 方式一:在语句声明的前面直接加上export关键字
- 方式二:将所有需要导出的标识符,放到export后面的 {}中
- 注意:这里的 {}里面不是ES6的对象字面量的增强写法,{}也不是表示一个对象的;
- 所以: export {name: name},是错误的写法;
- 方式三:导出时给标识符起一个别名
- 通过as关键字起别名
- 三种导出方式
3.import关键字
- import关键字负责从另外一个模块中导入内容
- 导入内容的方式也有多种:
- 方式一:import {标识符列表} from '模块';
- 注意:这里的{}也不是一个对象,里面只是存放导入的标识符列表内容;
- 方式二:导入时给标识符起别名 通过as关键字起别名
- 方式三:通过 * 将模块功能放到一个模块功能对象(a module object)上
4. export和import结合使用
- 补充:export和import可以结合使用
- 为什么要这样做呢?
- 在开发和封装一个功能库时,通常我们希望将暴露的所有接口放到一个文件中;
- 这样方便指定统一的接口规范,也方便阅读;
- 这个时候,我们就可以使用export和import结合使用;
- 三种写法:
// 整个文件夹统一导出的出口
// 写法一:
import { formatCount, formatDate } from './formare.js'
export {
formatCount,
formatDate
}
// 优化一:
// export和formare结合使用
export { formatCount, formatDate } from './formare.js'//表示从formare.js进行导入,再从这里进行导出
// 优化二·:
// export和formare结合使用,表示将formare里面的有东西进行导入,再导出。
export * from './formare.js'//表示从formare.js进行导入,再从这里进行导出。
5. default用法
- 前面我们学习的导出功能都是有名字的导出(named exports):
- 在导出export时指定了名字;
- 在导入import时需要知道具体的名字;
2. 还有一种导出叫做默认导出(default export)
- 默认导出export时可以不需要指定名字;
- 在导入时不需要使用 {},并且可以自己来指定名字;
- 它也方便我们和现有的CommonJS等规范相互操作;
3. 注意:在一个模块中,只能有一个默认导出(default export)
6. import函数
- 通过import加载一个模块,是不可以将其放到逻辑代码中的,比如:
执行代码之前,浏览器会提前将foo的资源下载下来,进行解析。
3. 为什么会出现这个情况呢?
- 这是因为ES Module在被JS引擎解析时,就必须知道它的依赖关系;
- 由于这个时候js代码没有任何的运行,所以无法在进行类似于if判断中根据代码的执行情况;
- 甚至拼接路径的写法也是错误的:因为我们必须到运行时能确定path的值;
- 但是某些情况下,我们确确实实希望动态的来加载某一个模块:
- 如果根据不同的条件,动态来选择加载模块的路径;
- 这个时候我们需要使用
import()函数来动态加载; - import函数返回一个
Promise,可以通过then获取结果;
7. import meta
import.meta是一个给JavaScript模块暴露特定上下文的元数据属性的对象。
- 它包含了这个模块的信息,比如说这个模块的URL;
- 在ES11(ES2020)中新增的特性;
8. ES Module的解析流程
- ES Module是如何被浏览器解析并且让模块之间可以相互引用的呢?
- ES Module的解析过程可以划分为三个阶段:
- 阶段一:构建(Construction),根据地址查找js文件,并且下载,将其解析成模块记录(Module Record);
- 阶段二:实例化(Instantiation),对模块记录进行实例化,实例化成一个,模块环境记录,并且分配内存空间,解析模块的导入和导出语句,把模块指向 对应的内存地址。
- 阶段三:运行(Evaluation),运行代码,计算值,并且将值填充到内存地址中;
- 整体逻辑
4. 各阶段逻辑黄金重点
- 阶段一:构建阶段
- 阶段二和三:实例化阶段 – 求值阶段