模块化——DOM脚本与语言的分水岭脚本还是语言?当BrendanEich设计第一个JavaScript版本时,他可能不知道他的项目在过去20年中会如何发展。目前,语言规范已经有六个主要版本,并且其改进工作仍在继续。老实说,JavaScript从来都不是一种完美的编程语言。JS的弱点之一是模块化,更明显的是它的缺失。实际上,当您仅使用脚本语言制作雪花落在页面上的动画或表单验证时,当所有内容都可以在同一全局范围内生存和交互时,为什么您需要关心代码和依赖项的隔离?随着时间的推移,JavaScript已经转变为一种通用语言,因为它用于在各种环境(浏览器、移动设备、服务器、物联网)中构建复杂的应用程序。随着越来越多的代码使您的应用程序变得过于脆弱,通过全局范围与程序组件交互的旧方法变得不可靠。这就是创建各种模块化实现以简化JavaScript应用程序创建的原因。两个核心问题命名冲突从出现的那一刻起,JavaScript就使用全局对象窗口作为所有没有用var关键字定义的变量的存储。在早期,它很方便,因为JavaScript代码倾向于解决不需要很多代码行的小任务。但是,当应用程序的代码库变大时,该语言的这一特性开始由于名称冲突而导致严重的错误。使用代码共享JavaScript构建大型应用程序的另一个不便之处是需要在大多数常见的ES5浏览器环境中使用脚本标签明确指定插件脚本。如果您关心应用程序的源代码应该是可维护的,那么您需要将它拆分成独立的部分。因此,文件的数量可能非常大。大量的文件,手动控制脚本(即通过脚本标签在页面上放置脚本)变得非常繁琐,因为首先你要记住在页面中放置必要的脚本,其次,保持正确的脚本标签顺序,以便解决文件之间的所有依赖关系。JSModularizationProcessOverviewDirectlyDefineDependencies(1999):由于当时js文件非常简单,所以模块化的方式非常简单粗暴——通过全局方法定义和引用模块。这种定义方式和现在的commonjs非常相似,不同的是commonjs是以文件作为模块,而这种方式可以在任意文件中定义模块,模块不与文件关联。ClosureModularizationMode(2003):闭包方法解决了变量污染问题。闭包中返回模块对象,只需要对外暴露一个全局变量即可。模板依赖定义(2006年):此时流行后端模板语法,通过后端语法聚合js文件实现依赖加载,但挂在可维护性上。注解依赖定义(2006):几乎与模板依赖定义同时出现。与1999方案不同的是,不是只有模块定义的方式,而是最终以文件为单位定义模块。通过lazyjs加载文件的同时读取文件注释,继续递归加载剩余文件。外部依赖定义(2007):这种定义方式在cocos2d-js开发中比较常用。它的核心思想是将依赖提取到一个单独的文件定义中。这种方法不利于项目管理。毕竟,依赖是在代码之外提取出来的。我对吗?一定要看两端吗?所以才会有一种方法,通过webwpack打包成文件,暴力替换成commonjs。沙盒模式(2009):这种模块化的方式非常简单暴力。将所有模块都塞进一个sanbox变量并不能解决明显的冲突问题。毕竟都是塞进了一个sandbox对象,而且Sandbox对象也需要全局定义,有被覆盖的风险。模块化需要保证全局变量尽可能干净,而目前的模块化方案在这方面做得并不好。DependencyInjection(2009):被称为angular1.0,依赖注入的思想在react、vue等流行框架中得到广泛应用。但是依赖注入和解决模块化问题还差得很远。CommonJS(2009):真正解决了模块化的问题,从节点端逐渐工作到前端,前端需要通过构建工具来模拟。AMD(2009):两者是同一时期的产物。本方案主要解决前端动态加载依赖。与commonJs相比体积更小,按需加载。umd(2011):兼容CommonJS和Amd,其核心思想是,如果在commonjs环境下(有module.exports但没有define),函数执行结果交给module.exports实现Commonjs,否则使用define在Amd环境下,AchieveAmd。LabeledModules(2012):和Commonjs很像,也没什么不对,但生不逢时,Commonjs和Amd相遇,只会被遗忘。YModules(2013):自从CommonjsAmd发布后,文章也列出了这个方案,想必有其独到之处。核心思想是用provide代替return,可以控制模块的结束时机,处理异步结果;获取第二个参数module,修改其他module的定义(虽然扩展性很好,但是在项目中是乱七八糟的)。ES2015Modules(2015):是我们目前的模块化方案,浏览器还没有实现,大部分项目已经通过babel或者typescript提前体验过了。围绕解决命名空间问题的阶段,Nameflag模式增加了Global上的变量数量,直接暴露出来,不做任何封装。Namespace模式减少了Global上的变量数量。它本质上是一个对象,根本不安全。IIFE模式函数是JavaScript中唯一的一个。LocalScopeModule模式引入了简单的依赖关系,将全局函数注入匿名函数现代模块实现的基石深入模块模式——处理不同版本包之间的关系——当考虑到加载顺序时事情变得复杂导出模块需要maintaintheloadingorderLoosely增强各个模块的松散协议异步加载,不再考虑加载顺序——当考虑不同版本的集成时,情况就变得复杂了![uploading...]()
