JS模块化背景js本身简单的页面设计:页面动画+表单提交,没有模块化,也没有命名空间的概念对JS模块化的需求越来越大并且不同的文件被同一个模板消费//当时就认识到:文件分离是最基本的问题:全局范围的污染=>不利于大型项目的开发和多人团队共建Variableletcount=0//代码块1constincrease=()=>++count//代码块2constreset=()=>{count=0}increase()reset()利用函数的块级作用域(()=>{letconut=0//...})只定义一个函数,不执行它,如果立即执行(()=>{letConut=0//...})()最初实现了一个最简单的模块(通过立即函数执行)尝试定义一个最简单的模块constiifeModule=(()=>{letcount=0//codeblock1constincrease=()=>++count//代码块2constreset=()=>{count=0}return{//代码块1增加:()=>++count,//代码块2重置:()=>{count=0}}})()iifeModule.increase()iifeModule.reset()问题:如果有额外的依赖,如何优化iife?-参数调用优化1:IIFEconst依赖其他模块iifeModule=((dependencyModule1,dependencyModule2)=>{letcount=0return{//代码块1增加:()=>++count,//代码块2重置:()=>{count=0}}})(dependencyModule1,dependencyModule2)iifeModule.increase()iifeModule.reset()问:你知道jquery的依赖处理和模块加载方案吗?/知道传统IIFE是怎么解决多方依赖问题的吗?答:IIFE+传参其实jquery等框架其实应用了revealingmodule(揭示模式)constiifeModule=((dependencyModule1,dependencyModule2)=>{letcount=0//codeblock1constincrease=()=>++count//代码块2constreset=()=>{count=0}//只暴露接口,不暴露方法return{increase,reset}})(dependencyModule1,dependencyModule2)iifeModule.increase()iifeModule.reset()成熟期CJS-CommonJSnode开发的一套程序特性:通过module+exports暴露通过require调用其他模块模块组的借口编织方法在main.js文件中//引用constdependencyModule1=require(dependencyModule1)constdependencyModule2=require(dependencyModule2)//处理letcount=0//代码块1constincrease=()=>++count//代码block2constreset=()=>{count=0}//做一些与引入依赖相关的事情...//暴露接口exports.increase=increaseexports.reset=resetmodule.exports={increase,reset}模块使用const{increase,reset}=require(main.js)increase()reset()可能会要求真正执行处理并转换成立即执行函数的组合CJS和IIFE//需要穿参数(function(){constdependencyModule1=require(dependencyModule1)constdependencyModule2=require(dependencyModule2)//业务逻辑...}).call(thisValue,exports,require,module)CJS优点:CommonJS最先在服务端实现,解决依赖和全局变量pollu问题从框架层面来说CJS缺点:主要针对服务端解决方案,都是同步引入的,对异步拉取依赖集成不太友好。新问题——通过异步加载异步依赖AMD规范+允许自定义回调函数经典实现框架:require.js新定义方法://通过deifine定义一个模块,然后require加载/***id:模块名*[depends]:依赖模块*callback:工厂方法*/define(id,[depends],callback)require([module],callback)模块定义方法:define('amdModule',['dependencyModule1','dependencyModule2'],(dependencyModule1,dependencyModule1)=>{//处理让count=0//代码块1constincrease=()=>++count//代码块2constreset=()=>{count=0}return{increase,reset}})Importmodule:require(['amdModule'],amdModule=>{amdModule.increase()})问:想兼容amdModule中已有的代码怎么办?define('amdModule',[],require=>{//引用constdependencyModule1=require(dependencyModule1)constdependencyModule2=require(dependencyModule2)//processletcount=0//codeblock1constincrease=()=>++count//代码块2constreset=()=>{count=0}//做一些与引入依赖相关的事情...//暴露接口exports.increase=increaseexports.reset=resetmodule.exports={increase,reset}})Q:AMD使用revealingdefine('amdModule',[],(require,exports,module)=>{//referenceconstdependencyModule1=require(dependencyModule1)constdependencyModule2=require(dependencyModule2)//processletcount=0//codeblock1constincrease=()=>++count//codeblock2constreset=()=>{count=0}//做一些与导入依赖相关的事情......//暴露接口exports.increase=increaseexports.reset=reset})define(require=>{constotherModule=require('amdModule')otherModule.increase()otherModule.reset()})问:兼容使用AMD和CommonJS?答:UMDUMD的出现(define('amdModule',[],(require,exports,module)=>{//参考constdependencyModule1=require(dependencyModule1)constdependencyModule2=require(dependencyModule2)//processletcount=0//代码块1constincrease=()=>++count//代码块2constreset=()=>{count=0}//做一些与导入依赖相关的事情...//暴露接口exports.increase=increaseexports.reset=reset}))(//目标是区分CommonJS或AMDtypeofmodule==="object"&&module.exports&&typeofdefine!=="function"?//是CommonJSfactory=>module.exports=factory(require,exports,module)://是AMDdefine)优点:适合在浏览器中加载异步模块,可以并行加载多个模块缺点:会有引入成本,CMD规范不能按需加载。主应用框架可以按需加载sea.jsdefine('module',[],(require,exports,module)=>{let$=require('jquery');//jquery相关代码letdependencyModule1=require('dependencyModule1')//dependencyModule1相关逻辑})优点:按需加载,依赖就近缺点:依赖包装,加载逻辑存在于每个模块中,扩展模块体积ES6模块化新时代新定义:导入keyword——importexportkeyword——export模块导入、导出和定义esModule.js//importimportdependencyModule1from'dependencyModule1'importdependencyModule2from'dependencyModule2'//implementletcount=0exportconstincrease=()=>++countconstreset=()=>{count=0}//exportexportdefault{reset}导入模板的地方:node:import{reset}from'esModule.js'reset()importesModulefrom'esModule.js'esModule.reset()优点(重要性):以最统一的形式集成js模块化缺点(局限):本质上还是用依赖分析来解决模块化的新思路——前端工程背景的基础问题——运行时的依赖分析前端模块化的解决方案取决于运行时分析解决方案:离线执行grunt、gulp、webpack
