模块化——DOM 脚本和语言的分水岭
脚本还是语言?
当 Brendan Eich 设计 JavaScript 的第一个版本时,他可能不晓得他的我的项目在过来 20 年将如何倒退。目前,该语言标准曾经有六个次要版本,其改良工作仍在持续。
诚实说,JavaScript 素来都不是完满的编程语言。JS 的弱点之一是模块化,更分明地说,它的缺席。的确,当您仅将脚本语言用于页面上飘落的雪花动画或表单验证时,当所有都能够在同一个全局范畴内生存和交互时,为什么您须要关怀代码和依赖项的隔离?
随着工夫的推移,JavaScript 曾经转变为一种通用语言,因为它开始用于在各种环境(浏览器、挪动设施、服务器、物联网)中构建简单的应用程序。通过全局范畴交互程序组件的旧办法变得不牢靠,因为越来越多的代码往往会使您的应用程序过于软弱。这就是为什么为了简化创立 JavaScript 应用程序而创立了各种模块化实现。
两个外围问题
- 命名抵触
从它呈现的那一刻起,JavaScript 就应用全局对象窗口作为没有应用 var 关键字定义的所有变量的存储。在晚期,它十分不便,因为 JavaScript 代码偏向于解决不须要很多代码行的小工作。然而当应用程序的代码库变得很大时,该语言的这一个性开始因为名称抵触而导致重大的谬误。 - 代码共享
JavaScript 构建大型应用程序的另一个不便之处是须要在最常见的 ES5 浏览器环境中应用 script 标签显式指定插件脚本。如果您关怀应用程序的源代码应该是可保护的,那么您须要将其拆分为独立的局部。因而,文件的数量可能十分大。对于大量文件,手动管制脚本(即通过脚本标签将脚本搁置在页面上)变得十分繁琐,因为首先您必须记住在页面中搁置必要的脚本,其次要放弃正确的程序 脚本标签,以便解决文件之间的所有依赖关系。
JS 模块化过程概述
间接定义依赖 (1999): 因为过后 js 文件非常简单,模块化形式非常简单粗犷 —— 通过全局办法定义、援用模块。这种定义形式与当初的 commonjs 十分神似,区别是 commonjs 以文件作为模块,而这种办法能够在任何文件中定义模块,模块不与文件关联。
闭包模块化模式 (2003): 用闭包形式解决了变量净化问题,闭包内返回模块对象,只需对外裸露一个全局变量。
模版依赖定义 (2006): 这时候开始风行后端模版语法,通过后端语法聚合 js 文件,从而实现依赖加载,但挂在可维护性上。
正文依赖定义 (2006): 简直和模版依赖定义同时呈现,与 1999 年计划不同的,不仅仅是模块定义形式,而是终于以文件为单位定义模块了,通过 lazyjs 加载文件,同时读取文件正文,持续递归加载剩下的文件。
内部依赖定义 (2007): 这种定义形式在 cocos2d-js 开发中广泛应用,其核心思想是将依赖抽出独自文件定义,这种形式不利于项目管理,毕竟依赖抽到代码之外,我是不是得中间找呢?所以才有通过 webwpack 打包为一个文件的形式暴力替换为 commonjs 的形式呈现。
Sandbox 模式 (2009): 这种模块化形式很简略,暴力,将所有模块塞到一个 sanbox 变量中,硬伤是无奈解决明明抵触问题,毕竟都塞到一个 sandbox 对象里,而 Sandbox 对象也须要定义在全局,存在被笼罩的危险。模块化须要保障全局变量尽量洁净,目前为止的模块化计划都没有很好的做到这一点。
依赖注入 (2009): 就是大家熟知的 angular1.0,依赖注入的思维当初已宽泛使用在 react、vue 等风行框架中。但依赖注入和解决模块化问题还差得远。
CommonJS (2009): 真正解决模块化问题,从 node 端逐步发力到前端,前端须要应用构建工具模仿。
Amd (2009): 都是同一期间的产物,这个计划次要解决前端动静加载依赖,相比 commonJs,体积更小,按需加载。
Umd (2011): 兼容了 CommonJS 与 Amd,其核心思想是,如果在 commonjs 环境(存在 module.exports,不存在 define),将函数执行后果交给 module.exports 实现 Commonjs,否则用 Amd 环境的 define,实现 Amd。
Labeled Modules (2012): 和 Commonjs 很像了,没什么硬伤,但生不逢时,碰上 Commonjs 与 Amd,那只有被人忘记的份了。
YModules (2013): 既然都出了 Commonjs Amd,文章还列出了此计划,肯定有其独到之处。其核心思想在于应用 provide 取代 return,能够管制模块完结机会,解决异步后果;拿到第二个参数 module,批改其余模块的定义(尽管很有拓展性,但用在我的项目里是个搅屎棍)。
ES2015 Modules (2015): 就是咱们当初的模块化计划,还没有被浏览器实现,大部分我的项目已通过 babel 或 typescript 提前体验。
围绕解决命名空间问题阶段
Nameflag 模式
- 减少 Global 上的变量数目
- 间接裸露,毫无封装性
Namespace 模式
- 缩小 Global 上的变量数目
- 实质是对象,一点都不平安
IIFE 模式
- 函数是 JavaScript 惟一的 Local Scope
Module 模式
- 引入简略的依赖,把全局函数注入到匿名函数中
- 古代模块实现的基石
模块模式深刻——不同版本包之间关系的解决
——当思考到加载程序时,状况就变得复杂
拓展加强
- 导入 MODULE,裁减属性,导出 MODULE
- 需保护加载程序
涣散加强
- 每个模块的涣散约定
- 异步加载,不再思考加载程序
——当思考到不同版本交融时,状况就变得复杂
Sub-modules 子模块
- 更上一层的封装
Porxy 模式
![上传中 …]()