随着应用的规模越来越庞大,嵌入网页的Js代码越来越庞大,越来越复杂。如果任由其发展,那么就会像下图所示。后期增加一个功能,对应用来的维护性来说将是指数级别的递增。
程序开发者不得不使用软件工程的方法,管理网页的业务逻辑。Js的模块化,封装化已经成为了一个迫切的需求。
一. 基础写法
封装是一种思想,它把特定的功能封装成一组方法。
只要把不同的函数以及变量简单地放在一起,就算是一个封装了的功能。
这种做法的缺点很明显:"污染"了全局变量,无法保证不与其他模块发生变量名冲突,而且模块成员之间看不出直接关系。
二. 对象写法
为了解决上面的缺点,可以把模块写成一个对象,所有的模块成员都封装放到这个对象里面。
但是,这样的写法会暴露所有模块成员,内部状态可以被外部改写。比如,外部代码可以直接改变内部计数器的值。
三. 立即执行函数写法
使用"立即执行函数"(Immediately-Invoked Function Expression,IIFE),可以达到不暴露私有成员的目的。
var module = (function(){
var count = 0;
function add(){
}
function plus(){
}
return {
addFunc : add,
pulsFunc : plus
}
})();
上面的写法无法直接从外部获取count变量,上面的封装就是js的常用封装方法。
四. 放大模式写法
如果一个模块很大,必须分成几个部分,或者一个模块需要继承另一个模块,这时就有必要采用"放大模式"(augmentation)。
上面的代码为module模块添加了一个新方法zhanyisc3(),然后返回新的module模块。
五. 宽放大模式
在浏览器环境中,模块的各个部分通常都是从网上获取的,有时无法知道哪个部分会先加载。如果采用上一节的写法,第一个执行的部分有可能加载一个不存在空对象,这时就要采用"宽放大模式"。
与"放大模式"相比,"宽放大模式"就是"立即执行函数"的参数可以是空对象。
六. 输入全局变量写法
独立性是模块的重要特点,模块内部最好不与程序的其他部分直接交互。
为了在模块内部调用全局变量,必须显式地将其他变量输入模块。
上面的module模块需要使用jQuery库,就把该库当作参数输入module。这样做除了保证模块的独立性,还使得模块之间的依赖关系变得明显。上面介绍的是一个js文件内部的封装过程。
但是如果一个应用中一个页面需要加载很多个js文件,常见的写法如下:
这样的写法有很大的缺点。首先,加载的时候,浏览器会停止网页渲染,加载文件越多,网页失去响应的时间就会越长;其次,由于js文件之间存在依赖关系,因此必须严格保证加载顺序(比如上例的1.js要在2.js的前面),依赖性最大的模块一定要放到最后加载,当依赖关系很复杂的时候,代码的编写和维护都会变得困难。
有没有办法来解决上面所提到的问题呢?答案是有的,这就是多个js协作工作的问题,请接着往下看。
七. 模块化规范
俗话说没有规矩不成方圆,模块化没有规范,每个人都按照自己的想法来写,对别人理解起来就很费时费力,不利于沟通传播和学习。因此js就制定了这样一个规范,用于模块的加载,别人想要什么,按照规范来加载使用就好了。
目前,通行的js模块规范有CommonJS和AMD。下面就来说说这两种加载方式。
八. CommonJS
在CommonJS规范中,有一个全局性方法require(),用于加载模块。假定有一个模块hello.js,就可以像下面这样加载。
上面的伪代码中,必须等hello.js加载完成。才能调用该模块的方法,也就是说,如果加载时间很长,整个应用就会停在那里等。
这个重大的局限,使得CommonJS规范不适用于浏览器环境,如果网速很慢,加载js的等待时间过长,浏览器处于"假死"状态。
因此,浏览器端的模块,不能采用"同步加载"(synchronous),只能采用"异步加载"(asynchronous)。这也是AMD规范诞生的背景。
九. AMD
AMD是"Asynchronous Module Definition"的缩写,意思就是"异步模块定义"。它采用异步方式加载模块,模块的加载不影响它后面语句的运行。所有依赖这个模块的语句,都定义在一个回调函数中,等到加载完成之后,这个回调函数才会运行。
AMD也采用require()语句加载模块,但是不同于CommonJS,它要求两个参数如下所示:
将上面的方法改为AMD方式异步加载写法如下:
它更适合浏览器环境。
上面提到了AMD加载其他模块,那么所谓的其他模块如hello.js这样的独立的js文件在AMD规范中该如何写呢?
这里也要使用定义的规范函数来定义它就是define()函数。如下hello.js的定义为:
如果这个hello.js模块还依赖其他模块,那么define()函数的第一个参数,必须是一个数组,指明该模块的依赖性。
至此一步一步封装js到这里就告一段落啦。喜欢的小伙伴,记得点个关注哦!
网友评论