可能在频繁使用复制粘贴解决重复代码之后,才能明白学习模块化开发的重要性。参考了阮一峰前辈的日志以后,稍稍理清了一些思路。随着页面功能复杂化,页面需要编写的js代码也越来越多,页面开发转而使用软件工程的方法进行分工合作、进度管理等等。简单的铺写javascript程序满足不了这些需求,而javascript脚本语言的特性也不满足模块化开发的基本需要 – 没有class 和 module的概念。按照javascript一贯的作风,则是用现有的运行环境下,模拟出模块的概念。
类比我们批量构建对象时的经验,从工厂模式到构造函数,再到原型模式,再发展为构造函数与原型组合的模式,每次改进都解决了之前模式固有的弊端,也进一步提出了新的问题。模块是实现特定功能的一组方法,模拟模块化模式的过程和构建对象模式的过程也很相似。
原始写法
以函数的形式拆解代码,把不同的函数放在一起则构成一个模块。
1 | function module1Func1() { |
在使用这种原始的模块时,调用函数就可以了。但是这种模式下,函数名是在全局声明的,无法保证不与其他变量名、函数名相冲突。此外,模块成员之间看不出联系,如果不再函数名上或注释里说明,几乎是无法区分的。
对象写法
为了解决原始写法里成员之间没有联系、全局变量名易导致冲突的问题,将模块中的函数写成对象的属性方法,在使用的时候,调用这个对象的属性。
1 | var module = { |
这种写法将函数联系在一起,但是却没有给予他们恰当的保护,外部可以轻易改写模块对象内部的方法和变量,而为了保证模块的高复用性和可靠性,保护模块内部状态不被篡改是有必要的。
立即执行函数
函数有一种显而易见的特性:它的作用域内的变量和方法对外界是不可见的。利用函数的这种特性,可以有效的保护模块内部数据和方法不被篡改以及保证模块本身的可靠性。
1 | var module = (function () { |
到这里,好像已经完美解决了日常使用模块的需要,需要注意的是,由于模块的独立性,模块内部的程序是不直接与外界直接交互的,所以为了使模块能够的调用全局变量,使用模块时应该显式的将所需变量传入模块。
1 | module.func1(args1 , args2 ,..); |