我们可以使用函数和闭包来实现模块,模块是一个提供接口却隐藏状态和实现的函数或者说是对象。通过使用函数创建模块,我们几乎可以摈弃全局变量的使用。
举例:
需要实现一个方法,任务是寻找字符串中的html字符实体并把他们替换成对应的字符,这里就需要在一个对象中保存字符实体的名称和对应的字符。
我们在哪边存放这个对象呢?可以放在全局变量中,也可以放在该函数的内部。但是全局变量是魔鬼,放在函数内部的话会带来运行的时候消耗,因为每次执行该函数的时候该字面量都会被赋值一次
最理想的做法就是把他放在一个闭包中,而且也许可以提供一个增加更多字符实体的扩展方法
String.prototype.deentityify = function(){ var entiry = { quto:'"', lt:'<', qt:'>' }; // 通过执行函数,来返回所需要创建的函数。 return function(){ return this.replace(/$([^&;]+;)/g,function(a,b){ var r = entiry[b]; return typeof r === 'string' ? r:a; }) }();}
模块模式利用了函数作用域和闭包来创建被绑定对象和私有成员的关联。
模块模式的一般形式:
一个定义了私有变量和函数的函数,利用闭包创建可以访问私有变量和函数的特权函数,最后返回这个特权函数,或者把他们保存到一个可以访问到的地方。
使用模块模式就可以不使用全局变量了。
对于模块模式也可以创建安全的对象
var serialMarker = function(){ var prefix = ""; var seq = 0; return { setPrefix : function(p){ prefix = String(p); }, setSeq : function(s){ seq = s; }, genSys : function(){ var result = prefix + seq; seq += 1; return result; } }}var seqer = serialMarker(); seqer.setPrefix('p'); seqer.setSeq(1000); var unique = seqer.genSys(); console.log(unique); // p1000
由于提供的方法中没有使用到this对象,因此没有办法去破坏方法,除非调用提供的方法去修改 seq 和 prefix 参数,否则无法修改。 对于 seqer 对象是可变的,所以他的方法可能会被替换掉,但是替换掉的方法仍然无法访问私有成员。