Module

最新更新: 2018-09-18 15:20:29 阅读: 21次

Module模式的基本特征

  1. 模块化,可重用
  2. 封装了变量和function,和全局的namaspace不接触,松耦合
  3. 只暴露可用public的方法,其它私有方法全部隐藏

基本用法


var Calculator = function (eq) {
    //这里可以声明私有成员  
  var eqCtl = document.getElementById(eq);   
       return {        // 暴露公开的成员  
      add: function (x, y) {   
         var val = x + y;    
        eqCtl.innerHTML = val;     
   }    };};


我们可以通过如下的方式来调用:


var calculator = new Calculator('eq');
calculator.add(2, 2);


匿名闭包

匿名闭包是让一切成为可能的基础,而这也是JavaScript最好的特性,我们来创建一个最简单的闭包函数,函数内部的代码一直存在于闭包内,在整个运行周期内,该闭包都保证了内部的代码处于私有状态。

引用全局变量

JavaScript有一个特性叫做隐式全局变量,不管一个变量有没有用过,JavaScript解释器反向遍历作用域链来查找整个变量的var声明,如果没有找到var,解释器则假定该变量是全局变量,如果该变量用于了赋值操作的话,之前如果不存在的话,解释器则会自动创建它,这就是说在匿名闭包里使用或创建全局变量非常容易,不过比较困难的是,代码比较难管理,尤其是阅读代码的人看着很多区分哪些变量是全局的,哪些是局部的。



现在很多类库里都有这种使用方式,比如jQuery源码。

不过,有时候可能不仅仅要使用全局变量,而是也想声明全局变量,如何做呢?我们可以通过匿名函数的返回值来返回这个全局变量,这也就是一个基本的Module模式,来看一个完整的代码

扩展


Module模式的一个限制就是所有的代码都要写在一个文件,但是在一些大型项目里,将一个功能分离成多个文件是非常重要的,因为可以多人合作易于开发。再回头看看上面的全局参数导入例子,我们能否把blogModule自身传进去呢?答案是肯定的,我们先将blogModule传进去,添加一个函数属性,然后再返回就达到了我们所说的目的,上代码:


var blogModule = (function (my) {  
  my.AddPhoto = function () {   
     //添加内部代码    
  };   
 return my;
} (blogModule)); 

松耦合扩展

上面的代码尽管可以执行,但是必须先声明blogModule,然后再执行上面的扩展代码,也就是说步骤不能乱,怎么解决这个问题呢?我们来回想一下,我们平时声明变量的都是都是这样的:


var cnblogs = cnblogs || {} ;


var blogModule = (function (my) {    
// 添加一些功能  
         return my;
} (blogModule || {}));  

紧耦合扩展

虽然松耦合扩展很牛叉了,但是可能也会存在一些限制,比如你没办法重写你的一些属性或者函数,也不能在初始化的时候就是用Module的属性。紧耦合扩展限制了加载顺序,但是提供了我们重载的机会,看如下例子:



var blogModule = (function (my) {
    var oldAddPhotoMethod = my.AddPhoto;
    my.AddPhoto = function () {
        // 重载方法,依然可通过oldAddPhotoMethod调用旧的方法   
 };
    return my;
} (blogModule));
克隆与继承




var blogModule = (function (old) {
    var my = {},
        key; 
   for (key in old) { 
       if (old.hasOwnProperty(key)) {
            my[key] = old[key]; 
       }    }
    var oldAddPhotoMethod = old.AddPhoto;
    my.AddPhoto = function () {
        // 克隆以后,进行了重写,当然也可以继续调用oldAddPhotoMethod    }; 
   return my;
} (blogModule));


这种方式灵活是灵活,但是也需要花费灵活的代价,其实该对象的属性对象或function根本没有被复制,只是对同一个对象多了一种引用而已,所以如果老对象去改变它,那克隆以后的对象所拥有的属性或function函数也会被改变,解决这个问题,我们就得是用递归,但递归对function函数的赋值也不好用,所以我们在递归的时候eval相应的function。不管怎么样,我还是把这一个方式放在这个帖子里了,大家使用的时候注意一下就行了。


跨文件共享私有对象

通过上面的例子,我们知道,如果一个module分割到多个文件的话,每个文件需要保证一样的结构,也就是说每个文件匿名函数里的私有对象都不能交叉访问,那如果我们非要使用,那怎么办呢? 我们先看一段代码:


var blogModule = (function (my) {
var _private = my._private = my._private || {},

_seal = my._seal = my._seal || function () {
delete my._private;
delete my._seal;
delete my._unseal;

},

_unseal = my._unseal = my._unseal || function () {
my._private = _private;
my._seal = _seal;
my._unseal = _unseal;
};

return my;
} (blogModule || {}));