模块化是将系统分离成独立功能的方法,这样咱们须要什么功能,就加载什么功能。编程
当一个项目开发得愈来愈复杂时,会遇到一些问题,例如:命名冲突、文件依赖等。数组
文件依赖就是,A负责a.js
组件的开发,B负责b.js
组件的开发,在a.js
文件里面可能引用了b.js
里面的某一个变量,而在项目运行时a.js
在b.js
以前加载,这个时候就会出现一些错误信息,可是a.js
和b.js
自己都没有错误,这就形成了咱们排错的一些困难,这种问题咱们称之为文件依赖的问题。浏览器
因此使用模块化开发时,能够避免以上问题,而且提高开发效率。缓存
怎么理解呢?在模块化开发里面,会把一个文件当作一个单独的做用域存在,它们定义的变量、函数都不会相互影响。那若是在a.js
里面依赖了b.js
,咱们就会进行声明,经过这种方式也能够减小文件依赖带来的BUG。服务器
而提高开发效率主要是从代码可复用性和可维护性来提高的。异步
总结:在生产的角度,模块化开发是一种生产方式,这种方式生产效率高,维护成本低。模块化
在早期的开发过程当中,就是将重复的代码封装搭到函数中,再将一系列的函数放到一个文件中。这种方式存在一些问题:存在污染全局变量、看不出相互的直接关系。函数
这种方式并不能解决根本的问题:命名冲突和文件依赖,因而演变为对象命名空间。ui
经过对象命名空间的形式,从某种程度上解决了变量命名冲突的问题,可是并不能从根本上解决命名冲突。存在问题:内部状态可被外部改写、命名空间愈来愈长。spa
利用此种方式将函数包装成一个独立的做用域,私有空间的变量和函数不会影响到全局做用域。这种方式至关于如今写插件的形式,解决了变量命名冲突的问题,可是没有解决下降开发复杂度的问题。
CommonJS
规范加载模块是同步的,也就是说,加载完成才执行后面的操做。Node.js
主要用于服务器编程,模块都是存在本地硬盘中,加载比较快,因此Node.js
采用CommonJS
规范。
CommonJS
规范分为三部分:module
(模块标识)、require
(模块引用)、exports
(模块定义)。 module
变量在每一个模块内部,就表明当前模块; exports
属性是对外的接口,用于导出当前模块的方法或变量;require()
用来加载外部模块,读取并执行js文件,返回该模块的exports
对象。
AMD也就是异步模块定义,它采用异步方式加载模块,主要针对的是浏览器端的模块规范。它经过define
方法去定义模块,require
方法去加载模块。
AMD定义:若是这个模块还须要依赖其余模块,那么define
函数的第一个参数,必须是一个数组,指明该模块的依赖。
define([tools], function(){});
复制代码
AMD模块的加载:
require(['modules'], callback);
复制代码
第一个参数['modules']
,是一个数组,里面的成员就是须要加载的模块;第二个参数callback
,则是加载成功以后的回调函数,例如加载math.js
:
require(['math'], function(){});
复制代码
require()
异步加载math
,浏览器不会失去响应;它指定的回调函数,只有前面的模块加载完成后才会运行,解决了依赖性的问题。
CMD即通用模块定义,CMD规范是国内发展出来的;正如AMD有require.js
,CMD有个浏览器的实现sea.js
。sea.js
要解决的问题和require.js
同样,只不过在模块定义方式和模块加载方式上有所不一样。
在CMD规范中,一个模块就是一个文件。代码的书写格式以下:
define(function (require, exports, module) {
// 模块代码
})
复制代码
require
是能够把其余模块导入进来的一个参数;exports
能够把模块内的一些属性和方法导出;module
是一个对象,上面存储了与当前模块相关联的一些属性和方法。CMD是按需加载,推崇依赖就近,延迟执行。文件是提早加载好的,只有在require
的时候才去执行文件;
define(function(require, exports, module){
var math = require('./math');
math.add();
})
复制代码
在ES6以前没有模块化,为了解决问题,提出了CommonJS,AMD,CMD;ES6模块化汲取CommonJS和AMD的优势,语法简洁,支持异步加载,将来能够成为浏览器和服务器通用的模块化解决方案。
ES6中模块的定义:ES6新增了两个关键字:export
和import
。export
用于把模块里的内容暴露出来,import
用于引入模块提供的功能。
ES6中模块的加载,import
加载模块:
import{bar,foo,test,obj} from './lib'
foo();
复制代码
注意:可使用export default
命令,为模块指定默认输出,一个模块只能有一个默认输出,因此export default
只能使用一次。
ES6模块运行机制:ES6模块是动态引用,若是使用import
从一个模块加载变量(即import foo from 'foo'
),变量不会被缓存,而是成为一个指向被加载模块的引用。等脚本执行时,根据只读引用,到被加载的那个模块中去取值。