Module 模块化
1. 模块起步
1-1 模块化规范
AMD
—— 异步模块定义规范,最初由require.js
库实现,用于浏览器的模块系统CommonJS
—— 为Node.js
服务器创建的模块系统UMD
—— 通用模块定义规范,作为通用的模块系统CMD
—— 阿里SeaJS
,用于浏览器的模块系统ES6 Module
——JavaScript
模块浏览器和服务器通用的模块系统
规范 | 描述 |
---|---|
CommonJS |
是服务器模块的规范,加载模块是同步的,也就是说,只有加载完成,才能执行后面的操作 |
AMD |
规范加载模块是异步的,并允许函数回调,不必等到所有模块都加载完成,后续操作可以正常执行,只要模块作为依赖时,就会加载并初始化 |
CMD |
CMD 规范和 AMD 类似通用模块定义,模块作为依赖且被引用时才会初始化,否则只会加载 |
UMD |
通用模块定义,UMD 是 AMD 和 CommonJS 的结合,实现跨平台的解决方案,先判断是否支持 Node.js 的模块(exports )是否存在,存在则使用 Node.js 模块模式。再判断是否支持 AMD (define 是否存在),存在则使用 AMD 方式加载模块 |
1-2 什么是模块?
ES Module
是 ES6
中提出的一个新的模块加载方式,完全可以取代 commonJs
和 AMD
两种模块加载方式,成为服务端和浏览器端模块加载的解决方案
ES6
模块的设计思想是尽量的静态化,使得编译时就能确定模块的依赖关系,以及输入和输出的变量,所以在资源加载速度和静态分析方面效率更高
export
—— 从当前模块外部访问的变量和函数import
—— 允许从其他模块导入功能
通过使用
<script type="module">
特性告诉浏览器,脚本应该被当作模块module
来对待
<!-- 添加type="module"让浏览器以模块解析脚本 -->
<script type="module">
// import 从其它模块引入功能
import {
module } from './module.js'
console.log(module)
</script>
// module.js
let module = 'ES Modules'
// export 从当前模块导出变量与方法
export {
module }
1-3 模块严格模式
在模块下始终在严格模式下运行,始终使用 use strict
- 变量必须声明后再使用
- 函数的参数不能有同名属性,否则报错
- 全局
this
执行undefined
<script>
// 不在模块下允许 this指向window
console.log(this); // window
</script>
<script type="module">
console.log(this); // defined
</script>
1-4 模块作用域
每个模块都有自己的作用域,一个模块中的作用域变量和函数在其他脚本中是不可访问的
对于模块,我们使用导入/导出而不是依赖全局变量
<script src="./normal.js"></script>
<!-- 模块A -->
<script type="module">
let module = 'module js'
</script>
<!-- 模块B -->
<script type="module">
// 对于模块只能使用导入导出 不能依赖全局变量
console.log(module)
//Uncaught ReferenceError module is not defined
</script>
<script>
// 不在模块下可访问外部组用于
console.log(normal)
console.log(module);
//Uncaught ReferenceError module is not defined
</script>
// normal.js
let normal = 'normal js'
1-5 模块解析
模块代码仅在第一次导入时被解析,当导出的对象或者其它类型数据时被修改了,后面再导入时获取的是修改后的新值
import.meta
对象包含关于当前模块的 url
信息,在浏览器环境中,它包含当前脚本的 URL
,或者如果它是在 HTML
中的话,则包含当前页面的 URL
<script type="module">
// import.meta获取当前脚本url
console.log(import.meta.url)
// 模块代码仅在第一次导入时被解析
// a模块导入module立即执行改变name属性 b模块引入module里的name是被更改的
import {
} from './module-a.js'
import {
} from './module-b.js'
</script>
// module.js
// 模块代码只会在第一次导入时解析
export let obj = {
name: 'jsx'
}
// module-a.js
import {
obj } from './module.js'
obj.name = 'ljj'
// module-b.js
import {
obj } from './module.js'
console.log(obj.name)
1-6 模块延迟
模块脚本是延迟加载的,与 defer
特性一样
- 外部模块脚本
<script type="module" src="...">
不会阻塞HTML
的处理,它们会与其他资源并行加载 - 模块脚本会等到
HTML
文档完全准备就绪,然后才会运行 - 保持脚本的相对顺序:在文档中排在前面的脚本先执行
<!-- 普通脚本不会延时加载不会等待文档加载会阻塞文档加载 -->
<!-- 1. defer -->
<!-- 2. 脚本放置元素后 -->
<!-- defer async只能用于外部引入的脚本延时加载 -->
<script src="./normal.js"