经常在面试或者其他文章看到关于模块化的问题,之前也只是寥寥看了几次,对于 CommonJS,AMD,ES6也说不出个所以然,于是今天抽空好好看了 红宝书第4版关于模块化的介绍,这里记录一下。
理解模块模式
初衷
在开发中肯定有设计大量三方库或者业务逻辑代码,较好的方式是将其分割为多个小模块,最后以一定的方式连接起来使用,这就是模块化兴起的初衷。
模块化一般包含什么?
模块化通常需要含一下几个点。<br/>
模块标识符
模块系统本质上是键/值实体,每个模块都有引用它的标志符,一般是路径或者文件名,部分模块系统也支持自定义标识符,这取决于哪种模块系统。
模块依赖
模块系统的核心就是是管理依赖了,脑海中大概有一张 A→B→C,这样的图就可以明白了。
模块加载
根据依赖,加载模块,在浏览器中只有整个依赖图都加载完成,才可以执行入口模块。
入口
这个就比较好理解了,相互依赖的模块必须指定一个模块作为入口(entry point),这也是代码执行的起点。
异步依赖
因为 JavaScript 可以异步执行,所以如果能按需加载就好了。换句话说,可以让 JavaScript 通知模块系统在必要时加载新模块,并在模块加载完成后提供回调。
1// 在模块 A 里面 2load('moduleB').then(function(moduleB) { 3 moduleB.doStuff(); 4});
动态依赖
可以在程序结构中动态引入模块
1if (loadCondition) { 2 require('./moduleA'); 3}
静态分析
模块中包含的发送到浏览器的 JavaScript 代码经常会被静态分析,分析工具会检查代码结构并在不实际执行代码的情况下推断其行为。
循环依赖
CommonJS、AMD 和ES6 在内的所有模块系统都支持循环依赖。
上面几点就是模块化的一些基本知识,接下来就看下我们比较关心的也面试偶尔问道的 CommonJS,AMD,ES6
CommonJS
CommonJS 规范主要概述了同步声明依赖的模块定义,一般用于服务端规范,比如node.js(Node.js使用了轻微修改版本的 CommonJS,因为 Node.js 主要在服务器环境下使用,所以不需要考虑网络延迟问题。),CommonJS模块语法是不能直接在浏览器中使用的
使用方法
1var moduleB = require('./moduleB'); 2module.exports = { 3 stuff: moduleB.doStuff(); 4}; 5/** 6 一般使用 require 和 module.exports的方式 7 可以赋值给变量,也可直接 require 进入,同时不管请求多少次,也只会加载一次 8 第一次加载后,模块就会缓存起来,供后续使用 9**/
AMD
CommonJS 以服务器端为目标环境,能够一次性把所有模块都加载到内存,而 AMD 异步模块定义,是以浏览器为目标。 AMD模块是以函数包装的方式来实现的,就避免暴露全局变量的方式,但是需要AMD加载库来实现。
1// ID 为'moduleA'的模块定义。moduleA 依赖 moduleB, 2// moduleB 会异步加载 3define('moduleA', ['moduleB'], function(moduleB) { 4 return { 5 stuff: moduleB.doStuff(); 6 }; 7});
ES6 模块
以上说的两种都需要模块加载器,ES6引入了模块规范,同时原生浏览器也开始支持,融入了 AMD 和 CommonJS的优点
1 2 //像我们平常写的 3 import { foo } from './fooModule.js' 4 export default 123 5 //或者 6 <script type="module"> 7 import './moduleA.js' 8 <script> 9 10<script type="module" src="./moduleA.js"></script> 11/** 12与传统脚本不同,所有模块都会像<script defer>加载的脚本一样按顺序执行。解析到<script 13type="module">标签后会立即下载模块文件,但执行会延迟到文档解析完成。 14**/
ES6模块的加载
既可以通过浏览器加载,也可以通过打包工具加载
ES6模块部分优点
1 1、模块只能加载一次。 2 2、模块可以请求加载其他模块。 3 3、模块顶级 this 的值是 undefined(常规脚本中是 window)。 4 4、模块中的 var 声明不会添加到 window 对象。 5 5、ES6 模块是异步加载和执行的,输出值的引用。
几个不同之处
11、CommonJS模块输出是值的拷贝,ES6 Module模块输出的值是引用 22、CommonJS是运行时加载,ES6 Module是编译是输出 33、AMD规范是采用异步方式,依赖前置必须一开始就写好,所有的依赖加载完成后才会执行回调函数里的内容
剩下关于 ES6 模块导入导出的使用方法和规则就不逐一介绍了。
