模块化开发方便代码管理,提高代码复用性,降低代码耦合。每个模块都有自己的范围。目前流行的模块化规范包括CommonJS、AMD、CMD、ES6import/export。CommonJS的主要实践者是nodejs。通常,module.exports用于输出模块输出,require用于导入模块。CommonJS一般采用同步加载[require/module.exports/exports]AMD遵守RequireJs规范,推荐pre-dependency(预执行)[require/defined]CMD遵守SeaJs规范,推荐near-dependency(延迟执行)[require/defined]ES6可以提前静态分析编译,不在运行时确认[import/export]开发过程简单封装->namespace/modules->scriptloader/modulesloader->同步加载CommonJS/AMD/CMD->ES6importexport/exportdefault->模块打包工具browserify/Webpack简单封装用法:简单的把不同的功能放在一起,当作一个模块。缺点:全局变量的“污染”,不保证不会和其他模块发生变量名冲突;模块成员之间看不到直接关系对象(命名空间)用法:将函数代码放入对象中,作为对象的属性优点:减少全局变量的个数,避免变量的全局污染缺点:本质是一个对象,并且这个对象会暴露所有的模块成员,内部状态可以被立即执行函数(IIFE)外部重写声明一个匿名函数并立即调用这个匿名函数。功能:创建一个独立的作用域。数据是私有的,外部只能通过暴露的方法操作这个作用域内的变量,外部无法访问(即避免“变量污染”)CommonJS导入导出:require&exports/module.exportsMain实践者:NodeJS模块导入语法:require(module)eg:varmath=require('math');数学.add(2,3);如果模块的输出是一个函数,则不能在exports对象上定义,而必须在模块中定义。导出上面的变量。//example2.jsmodule.exports=function(){console.log("helloworld")}//main.jsrequire('./example2.js')()AMD(异步模块定义)提倡前置依赖,在定义模块时,需要声明它所依赖的模块。requireJs提升时生成的规范模块定义define(id?,dependencies?,factory)id:string,模块名(可选)dependencies:array,即我们要加载的依赖模块(可选),使用相对路径factory:工厂方法,返回一个模块函数moduleimportrequire([module],callback)module:是一个数组,里面的成员是要加载的模块callback:是加载成功后的回调函数requireJS优点实现js文件的异步加载防止网页失去响应;管理模块之间的依赖关系根据依赖关系加载,方便代码编写和维护。异步加载模块,通过define定义一个模块,通过require导入模块。模块的加载不影响后续语句的执行。所有依赖于这些模块的语句都写在一个回调函数中。加载后,这个回调CMD(CommonModuleDefinition)提倡就近依赖(按需加载),在使用某个模块时需要。Sea.js推广过程中生成的标准模块定义define(id?,dependencies?,factory)类似于AMD//egdefine('hello',['jquery'],function(require,exports,module){//模块代码//返回模块对象});模块导入导出类似于AMDES6导入导出:import/export/exportdefaultexportdefault默认输出一个函数/变量当其他模块加载这个模块时,import命令可以为匿名函数指定任意值需要什么注意名称是此时导入命令后没有使用大括号//export-fn.jsexportdefaultfunction(){console.log('foo');}importfoofrom'export-fn.js'exportdefault命令也可以用在一个非匿名函数之前,它被视为一个匿名函数来加载exportdefault命令来指定模块的默认输出。一个模块只能有一个defaultexport,所以exportdefault命令只能使用一次。所以import命令后面不需要用大括号,因为它只能对应exportdefault命令。exportdefault本质上就是输出一个名为default的变量或方法,然后系统允许你给它取任何名字。export&exportdefault不同的是使用exportdefault时,对应的import语句不需要使用花括号。当export用于默认输出时,对应的import语句需要使用大括号//第一组exportdefaultexportdefaultfunctioncrc32(){//输出//...}importcrc32from'crc32';//输入//第二组导出exportfunctioncrc32(){//输出//...};import{crc32}from'crc32';//导入ES6、AMD、CommonJS,区分ES6模块,编译时就可以确定模块的依赖关系,以及输入输出变量。CommonJS和AMD模块都只能在运行时确定这些东西;CommonJS模块是对象,必须搜索对象属性才能输入。CommonJSmodulelet{stat,exists,readFile}=require('fs')整体加载fs模块(即加载fs),生成一个对象(_fs),然后从这个对象中读取3个方法。这种加载称为“runtimeloading”ES6moduleimport{stat,exists,readFile}from'fs'从fs模块加载3个方法,其他方法不加载,这种加载称为“编译时加载”或者静态加载CommonJSmoduleconstpath='./'+fileNameconstmyModual=require(path)动态加载,require加载哪个模块,import()动态加载只有runtime知道,proposal阶段,import()返回一个Promise对象import()模块加载成功后,这个模块会作为对象,作为then方法的参数import()类似于Node的require方法,不同的是前者是异步的加载,后者是同步加载。适用场景(1)按需加载(2)条件加载(3)动态模块路径注:关于ES6模块化详见阮一峰的es6入门模块modulees6和commonJS/AMD模块化差异模块化规范:CommonJS和AMD都有。前者用于服务器,后者用于浏览器。ES6提供了一个简单的模块系统,可以完全替代现有的CommonJS和AMD规范,成为浏览器和服务器的通用模块解决方案。ES6模块的设计思想是尽可能静态化,这样模块的依赖关系,以及输入输出变量都可以在编译时确定。CommonJS和AMD模块都只能在运行时确定这些东西。require和import的区别(commonJS和ES6模块化的区别)require/exports是CommonJS的一部分;import/export是ES6的新规范,require支持动态导入,import不支持,正在提议(babel下支持)require是同步导入,import是异步导入。require是值的副本,导出值的改变不会影响导入值;import是一个值引用,指向内存地址,导入的值会随着导出值的变化而变化es6entrymodulemodule
