在前端飞速发展的现状,模块化是一个非常重要的概念,像在 webpack 里,每一个文件就是一个模块。
模块之所以重要,是因为一个大程序如果只写在一个文件里,会非常的复杂、而且功能分割不够明确,难以在外部复用。
有了模块,我们就可以把一个大的程序按照功能拆分成一个个小模块,可以很方便的进行复用,也可以方便的提供给别人使用。
在 JavaScript 中,最主要的模块有 CommonJS、AMD、CMD 和 ES6 模块。
# CommonJS
在规范标准时代,Nodejs 的出现对前端的模块化发展具有非常大的促进作用
CommonJS 就是在 nodejs 中使用的模块标准,它的标准是这样的:
- 每个文件都是一个模块,每个模块具有独立的作用域。
- 模块可以被多次引用,缓存。在第一次被加载时会缓存下来,之后都直接从缓存中读取结果
- 加载某个模块 = 引入该模块的 module.export 属性
- module.export 输出的是值的拷贝,输出之后模块的变化不影响输出的值,相互独立。
- 按照代码引入的顺序进行加载
- CommonJS 规范加载模块是同步的。
写法示例:
let module = {} | |
module.exports = {} |
借助立即执行函数(IIFE),对 module 和 module.exports 进行赋值
(function(module,exports){ | |
... | |
}(module,module.exports)) |
# AMD
AMD 的全称是,Asynchronous Module Definition,如称呼所示,他的加载是异步的。
因为 nodejs 运行在服务器上,文件一般都是放在本地的,所以一般都是同步加载。但是如果在浏览器中运行,同步的方式显然非常不妥。
因此就推出了这个规范。
这个规范规定了如何定义模块,如何对外输出、引入依赖。
# CMD
CMD 全称为 Common Module Definition,它整合了 CommonJS 和 AMD 规范的特点。
它和 AMD 的主要区别有这些:
- AMD 需要异步加载模块,而 CMD 在加载模块可以选同步方式也可以选异步方式
- CMD 遵循的是依赖就近原则,AMD 遵循依赖前置原则。在 AMD 中,需要把模块需要的依赖都提前声明在依赖数组之中,在 CMD 中只需要在使用前引入。
# ES6 Module
**ES 模块的设计思想是尽量静态化,使得在编译时就能确定模块之间的依赖关系。** 像 CommonJS 和 AMD 模块就只能在运行时确定。
而且,ES 模块输出的是值的引用,像 CommonJS 输出的就是值的拷贝
因为 ES 模块设计成静态的,所以它有个明显的优势就是:
- 很容易就能分析出导入的依赖,也可以感知到导入的模块是否有被使用。
而且因为要设计成静态的,所以它的写法也有一定的限制:
- 只能在文件顶部引入依赖
- 导出的变量类型受到严格限制
- 变量不允许被重新绑定,引入的模块名只能是字符串常量
# Tree Shaking
通过这个算法,在模块没有明显被引用的时候,可以对代码进行去冗余。它的目的是减少应用中没有被实际运用的代码,在打包时就会剥离出来这些代码。
非常形象的比喻,摇晃一棵树(把一个大型应用比作一个模块构成的树),使得没有树枝连着的树叶掉落。