Skip to content

在概述那里有介绍过,AMD 和 CMD 是在 commonjs 出现之后到 ES 6 模块化出现之前使用的在浏览器端实现模块化的方案,现在我们在浏览器端都使用 ES 6 模块化方案,我们都作为了解即可。

首先我们应该要知道,为什么在浏览器端不能直接使用 commonjs 规范。首先,commonjs 在实现模块的导入时,会先读取模块文件,然后将文件放到一个函数环境内执行,执行完成后,将其内部的 module.exports 进行导出,就实现了模块的导入导出效果。

由于 commonjs 是同步执行的,所以将其引入浏览器就会出现严重的问题,因为浏览器端的模块导入大多场景下都是从远程服务器网络传输,相较于 node 的本地读取,网络传输的速度显然过于慢了,这导致了极大的性能浪费,同时,commonjs 需要读取文件,这显然需要浏览器去支持,但是浏览器厂商并不愿意支持这个标准,归根结底还是因为这属于一个社区标准,而非官方标准。

正因为这些问题,浏览器并没有立刻支持 commonjs 标准,同时前端有缺少模块化,于是又出现了新的社区规范,这个新的社区规范,显然,由于网络远程加载很耗时,所以新的规范就需要将这个导入做成异步模式,同时,书写模块的时候直接将他放到函数内执行,也可以解决问题,基于这种思想,就出现了 AMD 和 CMD 规范。

后来 ES 官方推出了一个官方的模块化标准,即 ES 6 模块化。彻底终结了 AMD 和 CMD 规范。

所以在浏览器环境下,我们建议使用 ES 6 模块化,实际上哪怕是 nodejs 也应该支持 ES 6 模块化,毕竟是 ES 的官方标准,但可惜的是 nodejs 目前并未完全支持该标准。

ES 6 模块化和 commonjs 存在很大的差异,commonjs 是在代码的运行过程中使用 require 函数导入模块,而 ES 6 模块化则是依赖预声明的方式导入。而相对应的,commonjs 这种就是依赖延迟声明。

依赖延迟声明的方式在一些情况下可以提高效率,但依赖关系比较模糊。由于 ES 6 模块化依赖预加载,所以导入代码一定要放在所有代码之前。

接下来看如何实现导入导出

首先,如果我们直积使用 script 引入一个 JS 文件,这个 JS 文件肯定不会识别为模块,或者说无法解决全局变量污染这些问题,所以我们在引入 JS 文件的时候,肯定要告诉浏览器,这玩意儿是不是一个模块,方式也很简单,就是在 script 标签中添加一个 type 属性,将属性值设置为 module 即可。

html
<script src="路径" type="module"></script>

此时导入的就是一个模块,而非普通的 JS 文件,只有识别为模块,才能使用 ES 6 的导入导出语句,这个时候这个 JS 文件内定义的变量将不会再污染全局变量。

我们要在模块内导出数据,使用 export 关键字,后面跟上一个声明表达式

js
export const a = 1;//导出了a,值为1
export function test(){//导出test,值为一个函数
	console.log("i am test");
}

很显然,在这种情况,export 后面必须跟一个声明语句,如果不是声明语句,比如直接给一个表达式,这是直接报错的语法,那如果我们就想这么干,就要导出一个变量,不使用声明语句,我们也有办法。

实际上,这种导出方式必须要带上一个名字,因为这种使用 export 导出是允许导出多个的,必须要加上名字予以区分,所以必须要用声明语句

js
const a = 1;
const b = 2;
export {a,b};

我们只需要给一个大括号,中间写上变量名写进去,就会将 a 变量和 b 变量导出,并且导出后变量名不变

既然有导出,就一定有导入,导入使用 import 关键字,语法非常类似

js
import {a,b} from "路径";

就可以将指定路径下的模块导入,拿到该模块导出的 a 和 b,赋值给变量 a 和 b。

js
import {a as b} from "路径"

上面这种写法可以用来在导入的时候给变量重新赋值,什么意思呢,就是导入指定路径模块拿到该模块中导出的 a 变量,这里给他重新赋值为 b 变量。

标准中,导入的路径必须使用 ./ 或 ../ 开头

导入的变量为常量,不可二次修改

js
import * as obj from "路径"

上面的代码会将指定路径的模块导出的内容全部导入,并形成一个对象,同时我们也应该注意,使用 * 导入时,必须使用 as 进行重命名。

在 ES 6 模块化中也有缓存机制,也就是说多次导入也只会执行一次

js
import "路径"

上面这种写法,也就是说我不想拿他的导出结果,我就只需要将这个模块运行一遍。同时不会使用任何缓存。

以上我们介绍的都是给带名字的导入和导出,这种我们叫做基本导出,实际上还有一种默认导入导出,当导入导出的变量名为 default 的时候,就变成了默认导入导出

js
const a = 1;
export {a as default};//这就是默认导出
js
export default 123;//这样直接写表达式也可以默认导出,更加方便

同样,在导入的时候,接受方式也一样

js
import {default as test} from "路径";

可以将指定路径下的模块中,默认导出的内容拿到,并取名为 test

我们还有更简单的导入方式

js
import test from "路径";
//等价于
import {default as test} from "路径";

我们也可以混合使用,但是其实并不常见,这里给个 DEMO 即可

js
import def,{a as a1} from "路径";
//默认导出放到def变量,拿到导出的a,作为a1

以笔记为镜,可以知得失