ES6 -- Module
本文最后更新于:2020年2月4日 下午
前言
讲到模块化,大家可能对 CommonJs
、AMD
、CMD
等规范都比较熟悉,ES6 也有 Module
的规范。本文是对Module
理解的整理。那依然先是问题三连:ES6 的 Module
是什么?用来解决什么问题?优点是什么?
是什么?
使用不同方式加载的 JS 文件,与原先脚本(script)加载方式相对。模块的真正力量在于按需导出和导入,而不在于将所有内容放在同一个文件
解决什么问题(切入点)
- 命名冲突(作用域)
- 让 JS 应用变得更加有条理
- 安全问题
优点是什么
- 自动运行在严格模式下,且无法跳出严格模式;
- 在模块的顶级作用域创建的变量,不会自动添加到共享的全局作用域,只存在于模块顶级作用域的内部;
- 模块顶级作用域的
this
为undefined
; - 模块中不允许
HTML
风格的注释,该问题是早期浏览器历史遗留特性; - 要提供给外部访问的代码,模块必须导出它们;
- 模块可以由别的模块导入绑定。
基本导出
export
我们可以在任意变量、函数、类声明之前加上 export
导出它们,没有被显式导出的将会在模块中保持私有
1 |
|
基本导入
import
可以通过 import
来导入被导出的模块,import
语句由两部分组成,被导入的标识符和导入标识符的来源:import { identifier1, identifier2 } from './module1.js'
1 |
|
需要注意的一点:无论使用多少次import
引入模块,该模块只会执行一次。在导出的模块执行之后,已被实例化的模块会保留在内存中,随时可被其它import
使用。同应用的其它模块,如使用import
引入该模块,使用的也是同一个实例模块
1 |
|
import和export有一个限制:无法在其它语句或表达式的内部使用,即必须在顶部作用域
1 |
|
题外话:在已完成的ES2020的提案中,有了新特性动态导入dynamic-import,可根据条件判断支持按需导入
默认导入-模块的默认值
我们可以通过default
为每一个模块设置一个且只能一个默认值
1 |
|
1 |
|
绑定导入,再导出
有时候我们会需要将导入的部分功能,再导出去作为另一个模块,比如作为库,这时候可以这样操作
1 |
|
完全导出需要注意一个问题,如果目标模块module
包含了默认值,那么就无法在当前模块new-module
再定义一个默认导出,始终遵守一个模块只能有一个默认导出的原则
无绑定的导入
有时候我们会对全局作用域对象进行一些附加操作,虽然模块中的代码不会自动共享到全局,但是我们还是可以在模块中对一些JS内置对象如Array
、Object
等进行访问,并且对这些对象的修改,可以反映到其它模块中
1 |
|
再通过import './extendArray.js'
将模块引入,这里虽然没有绑定的导出与导入,但依然是一个有效的模块,在引入该模块的模块中,所有的数组都可以使用pushAll()
方法
这种无绑定的导入,最有可能创建用于在旧环境运行新语法时做向下兼容的polyfill
和shim
加载方式
ES6定义了模块的语法,但未定义如何加载。
在web浏览器中使用模块
在ES6之前,已经存在多种方式可以在web应用中加载JS
- 使用
<script>
标签以及src
属性指定加载的位置,加载JS文件; - 使用
<script>
标签但不使用src
属性,嵌入内联的JS代码; - 加载JS代码文件并作为
Worker
(例如Web Worker
或Service Worker
)来执行
通过script加载模块
在使用script标签时,设置type属性为module,告诉浏览器将引入的代码作为模块。且会自动应用defer属性,将模块文件下载完后,等待网页文档全部解析完,再按照模块引入顺序依次执行。如果需要异步加载模块,则可以手动加上async属性
将模块作为Worker加载
为了支持模块加载,HTML标准的开发者给worker添加了第二个参数,该参数时带有type
属性的对象,默认值为script
,可以设置为module
,以此来加载模块
1 |
|
模块方式其中存在两点区别:
- worker脚本被限制只能从同源网页加载,worker模块不受限制;
- worker脚本可以使用
self.importScripts()
方法来将额外脚本引入worker,worker模块上的self.importScripts()
总是失败,因为应当换用成import
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!