背景
当下, 模块化已经深入到我们日常开发中。即:把一个大的 Javascript 程序分割成不同的部分, 哪个部分要被用到,就取那一部分, 按需取用。
早期, NodeJS 拥有这样的能力。 后来越来越多的库和框架也拥有了模块化的能力, 比如 CommonJS, 或者基于AMD模型的实现(比如RequireJs),还有后续的Webpack, Babel等。
一眼看上去, 我们不发现, ES6的模型系统和CommonJS语法非常的相似,毕竟ES6 的模型系统是从CommonJS时代发展过来的, 深受 CommonJS 影响。
看个简单的例子,比如在CommonJs中:
而在ES6中:
语法上,是非常相似的。
下面我们就主要看 import 和 export,和几个相关的特性,了解ES6 Modules的更多方面。
模块化的好处
模块化的好处主要是两点:
1. 避免全局变量污染
2. 有效的处理依赖关系
随着时代的演进, 浏览器原生也开始支持es6 import 和 export 语法了。
先看个简单的例子:
如果要处理事件,也是一样:
如果你想跑这个demo, 注意要起个简单的服务:
$ http-server
否则,你会看到一个 CORS 抛错。
至于抛错的具体原因和其他细节,不是本文讨论的重点, 感兴趣的可以阅读文章底部链接了解原因和相关细节。
严格模式
'use strict' 声明我们都不陌生, 在 es5 时代我们也经常使用, 一般是在文件顶部加这个声明,目的就是禁用Javascript中不太友好的一部分,有助于我们写更严谨的代码。
这个特性,在es6语法中是默认开启的, 如果代码里面有不太严格的代码,则会报错。例如:
下面是我从MDN中摘取的一些在严格模式
中被禁用
的部分:
export
Export 总览:
ES6模块只支持静态导出,你只可以在模块的最外层作用域使用export,不可在条件语句中使用,也不能在函数作用域中使用。
从分类上级讲, exports 主要有三种:
下面我就介绍一下常见的 exports用法。
1. Named exports (导出每个函数/变量)
具名导出,这种方式导出多个函数,一般使用场景比如 utils、tools、common 之类的工具类函数集,或者全站统一变量等。
只需要在变量或函数前面加 export
关键字即可。
我们也可以直接导出一个列表,例如上面的lib.js可以改写成:
2. Default exports (导出一个默认 函数/类)
这种方式比较简单,一般用于一个类文件,或者功能比较单一的函数文件使用。
一个模块中只能有一个export default默认输出。
export default 与 export的主要区别有两个:
不需要知道导出的具体变量名, import时不需要加 {}.
导出一个类:
注意这里默认导出不需要用{}。
3. Mixed exports (混合导出)
混合导出,也就是 上面第一点和第二点结合在一起的情况。
比较常见的比如 Lodash,都是这种组合方式。
再比如 Lodash 的例子:
一般情况下,export输出的变量就是在原文件中定义的名字,但也可以用 as 关键字来指定别名,这样做一般是为了简化或者语义化export的函数名。
有时候为了避免上层模块导入太多的模块,我们可能使用底层模块作为中转,直接导出另一个模块的内容如下:
export 只支持在最外层静态导出、只支持导出变量、函数、类
import
import 的用法和 export 是一一对应的,但是import支持静态导入和动态导入两种方式,动态import支持晚一些,兼容性要差一些。
另外需要注意的是,带有Module tag 的script , 是默认defer的, 没有必要在标签<script type="module">
里加 defer。
具体细节可以参考V8文档的Module 部分, 链接在文章底部的延伸阅读。
下面我就总结下import的基本用法:
1. Import All things
当export有多个函数或变量时,如文中export的第一点,可以使用 as 关键字来导出所有函数及变量,同时 as 后面跟着的名称做为 该模块的命名空间。
2. Import a single/multiple export from a module
从模块文件中导入单个或多个函数,与 * as namepage 方式不同,这个是按需导入。
如下例子:
和 export 一样,也可以用 as 关键字来设置别名,当import的两个类的名字一样时,可以使用 as 来重设导入模块的名字,也可以用as 来简化名称。 比如:
有时候我们只想import一个模块进来,比如样式,或者一个类库。
静态import在首次加载时候会把全部模块资源都下载下来.
我们实际开发时候,有时候需要动态 import。
例如实际用到某个模块才去加载:
es7的新用法:
总结
以上, 我总结了ES6 Module 的简单背景和 常见的 import , export 用法, 但这远远不是它的全部。篇幅太长,影响阅读体验。
如果想了解更多细节, 可以阅读底部的延伸阅读部分。
延伸阅读
https://2ality.com/2014/09/es6-modules-final.html
https://jakearchibald.com/2017/es-modules-in-browsers/
https://imweb.io/topic/582293894067ce9726778be9
https://v8.dev/features/modules