什么是模块?
所谓的模块话就是将一个系统拆分成各个独立的部分,每个部分实现一块功能,然后组合在一起形成系统。这样的有点如下:
- 可维护
- 可复用
- 可组合
JavaScript 程序本来很小——在早期,它们大多被用来执行独立的脚本任务,在你的 web 页面需要的地方提供一定交互,所以一般不需要多大的脚本。过了几年,我们现在有了运行大量 JavaScript 脚本的复杂程序,还有一些被用在其他环境
有必要提供一种将 JavaScript 程序拆分为可按需导入的单独模块的机制,二这个机制就是模块的规范,从js早期到现在,产生了很多的模块规范。接下来一一介绍一下:
文件划分
一个js文件即一个模块,然后再该js文件下定义模块的数据方法。最终将各个模块一script的方式引入到index.html中
优缺点:
- 一定程度上实现了模块划分。
- 变量同名
- 变量方法来源不清晰
- 依赖关系不明确
命名空间
命名空间的出现就是为了文件划分中,全局变量的问题。其实就是将每个文件模块下分散的数据和方法用对象包装起来(对象的名字做到唯一唯一性就好),然后放再window上。
优缺点
- 变量或者方法来源清晰了
- 只要人们按照一定规范命名,可以避免变量同名危险。
- 不太安全,变量并没有私有化。
- 但是依赖关系还是有问题,也就是script的加载顺序
IIFE
基于上诉不安全的原因,后来人们又提出了一个IIFE(立即执行函数)的方式,因为IIFE一运行就形成了一个私有的作用域,外界是没办法访问这个作用域下的变量的。
优缺点:
- 比命名空间更加安全
- 依赖关系还是无法解决。
CommonJS 规范(服务端-node)
最早比较正式的一个模块规范,主要用于node中。module.exports导出, require导入。语法如下:
// commonjs规范
特点如下:
- 得到node的支持
- 基于文件的,一个文件就是一个模块。
- 加载模块是同步的
缺点如下:
- CommonJS 的实现需要使用到node操作文件的api,所以它并不能运行再浏览器上
- CommonJS 本身约定以同步的方式进行模块加载,这种加载机制放在服务端是没问题的,一来模块都在本地,不需要进行网络 IO,二来只有服务启动时才会加载模块,而服务通常启动后会一直运行,所以对服务的性能并没有太大的影响。但如果这种加载机制放到浏览器端,会带来明显的性能问题。它会产生大量同步的模块请求,浏览器要等待响应返回后才能继续解析模块。也就是说,模块请求会造成浏览器 JS 解析过程的阻塞,导致页面加载速度缓慢。
AMD 规范
总之,CommonJS 是一个不太适合在浏览器中运行的模块规范,随后才又了AMD全称为Asynchronous Module Definition,即异步模块定义规范。模块根据这个规范,在浏览器环境中会被异步加载,而不会像 CommonJS 规范进行同步加载,也就不会产生同步请求导致的浏览器解析过程阻塞的问题了。
- 使用define定义一个模块
// main.js
define(["./print"], function (printModule) {
printModule.print("main");
});
// print.js
define(function () {
return {
print: function (msg) {
console.log("print " + msg);
},
};
});
- 使用require 加载一个模块
// module-a.js
require(["./print.js"], function (printModule) {
printModule.print("module-a");
});
AMD规范并没有得到浏览器的支持,如果要再项目中使用,需要借助第三方的 loader 来实现,也就是require.js库。例子如下:
总结:
- AMD规范更加使用运行到浏览器上,
- 不过代码阅读和书写都比较困难
UMD
兼容 AMD 和 CommonJS 的一个模块化方案,可以同时运行在浏览器和 Node.js 环境。不做多的介绍,已经不流行了
ES6 Module
ES6 Module 也被称作 ES Module(或 ESM), 是由 ECMAScript 官方提出的模块化规范,作为一个官方提出的规范,ES Module 已经得到了现代浏览器的内置支持。
ES Module 的兼容性问题,其实 ES Module 的浏览器兼容性如今已经相当好了,覆盖了 90% 以上的浏览器份额,
不仅如此,一直以 CommonJS 作为模块标准的 Node.js 也紧跟 ES Module 的发展步伐,从 12.20 版本开始正式支持原生 ES Module。也就是说,如今 ES Module 能够同时在浏览器与 Node.js 环境中执行,拥有天然的跨平台能力。