模块化开发,一个模块就是一个实现特定功能的文件,有了模块我们就可以更方便地使用别人的代码,要用什么功能就加载什么模块。
2.模块化开发的好处1)避免变量污染,命名冲突
2)提高代码利用率
3)提高维护性
4)依赖关系的管理
前端模块化规范从原始野蛮阶段现在慢慢进入“文艺复兴”时代,实现的过程如下:
3.1 函数封装我们在讲到函数逻辑的时候提到过,函数一个功能是实现特定逻辑的一组语句打包。在一个文件里面编写几个相关函数就是最开始的模块了
function m1() { // ... } function m2(){ //... }
这样做的缺点很明显,污染了全局变量,并且不能保证和其他模块起冲突,模块成员看起来似乎没啥关系。
3.2 对象为了解决这个问题,有了新方法,将所有模块成员封装在一个对象中
var module = new Object({ _count:0, m1:function (){ ```}, m2:function (){ ```} })
这样,两个函数就被包在这个对象中,看起来没有什么问题,当我们要使用的时候,就是调用这个对象的属性方法
module.m1()
那么问题来了,这样写法会暴露全部的成员,内部状态可以被外部改变,比如外部的代码可直接改变计数器的值
module._count = 10
3.3 立即执行函数(IIFE)var module = (function(){ var _count = 5; var m1 = function (){ ```}; var m2 = function (){ ```}; return{ m1:m1, m2:m2 } })()
以上就是模块化开发的基础中的基础,以后会说其他更深层次的模块化开发。
接下来了解几种模块化规范。
1)commonJS
commonJS由nodeJS发扬光大,这标志着js模块化正式登场。
一. 定义模块
根据commonJS规范,一个单独的文件是一个模块,每一个模块都是一个单独的作用域,也就是说,在该模块内部定义的变量,无法被其他模块读取,除非为global对象的属性。
二. 模块输出
模块只有一个出口,module.exports对象,我们需要把模块希望输出的内容放入该对象。
三. 加载模块
加载模块用require方法,该文件读取一个文件并且执行,返回文件内部的module.exports对象。
var name = 'Byron'; function printName(){ console.log(name); } function printFullName(firstName){ console.log(firstName + name); } module.exports = { printName: printName, printFullName: printFullName }
然后加载模块
var nameModule = require('./myModel.js'); nameModule.printName();
2)AMD
Asynchronous Moudule Definition,中文名是一步模块。它是一个在浏览器端模块化开发的规范,由于不是js原生支持,使用AMD规范进行页面开发需要用到对应的函数库,也就是大名鼎鼎的Require.js,实际上AMD是RequireJS在推广过程中对模块化定义的规范化的产出。
RequireJS主要解决两个问题:
1)多个js文件可能有依赖关系,被依赖的文件需要早于依赖它的文件加载到浏览器。
2)js加载的时候浏览器会停止页面渲染,加载文件越多,页面失去响应的时间越长。
//定义模块 define(['dependency'],function(){ var name = 'Byron'; function printName(){ console.log(name); } return { printName:printName } }) //加载模块 require(['myModule'],function(my){ my.printName(); })
语法:
requireJS定义了一个函数define,它是全局变量,用来定义模块。
define(id,dependencies,factory)
——id 可选参数,用来定义模块的标识,如果没有提供该参数,脚本文件名(去掉拓展名)
——dependencies 是一个当前模块用来的模块名称数组
——factory 工厂方法,模块初始化要执行的函数或对象,如果为函数,它应该只被执行一次,如果是对象,此对象应该为模块的输出值。
在页面上使用require函数加载模块;
require([dependencies], function(){});
require()函数接受两个参数:
——第一个参数是一个数组,表示所依赖的模块;
——第二个参数是一个回调函数,当前面指定的模块都加载成功后,它将被调用。加载的模块会以参数形式传入该函数,从而在回调函数内部就可以使用这些模块
AMD推崇的是依赖前置,被提前罗列出来并会背提前下载并执行,后来做了改进,可以不用罗列依赖模块,允许在回调函数中就近使用require引入并下载执行模块。
3)CMD
即common module definition
就像AMD有个requireJS,CMD有个浏览器实现的sea.js,sj要解决的问题和rj一样,只不过在模块定义方式和模块加载时机上有所不同。
cmd是sea.js在推广过程中的规范化产出,sea.js是另一种前端模块化工具,它的出现缓解了requireJS的几个痛点。
efine(id, deps, factory)
因为CMD推崇一个文件一个模块,所以经常就用文件名作为模块id;
CMD推崇依赖就近,所以一般不在define的参数中写依赖,而是在factory中写。
factory有三个参数:
function(require, exports, module){}
一,require
require 是 factory 函数的第一个参数,require 是一个方法,接受 模块标识 作为唯一参数,用来获取其他模块提供的接口;
二,exports
exports 是一个对象,用来向外提供模块接口;
三,module
module 是一个对象,上面存储了与当前模块相关联的一些属性和方法。
demo