深入理解Javascript:模块模式

本文转载自前端乱炖:Javascript 模块模式

1.Javascript 模块模式

假设现在我们有一个小型的Js库,目的是用来增加一个数字:

var jspy = {
  count: 0,

  incrementCount: function() {
    this.count++;
  },

  decrementCount: function() {
    this.count--;
  },

  getCount: function() {
    return this.count;
  }

};

但是,使用这个js库的人可以用jspy.count = 5 的方法来改变这个值。并不是我们的最初目的。在其他的编程语言中你可以定义一个私有变量,但是Javascript并不能“真正”定义私有变量。然而,我们可以通过操作Javascript来实现,这就引出了一个最流行的Javascript设计模式,模块模式。

针对上面问题的解决方案如下:

var jspy = (function() {
  var _count = 0;

  var incrementCount = function() {
    _count++;
  }

  var getCount = function() {
    return _count;
  }
  return {
    incrementCount: incrementCount,
    getCount: getCount
  };

})();

首先我们创造一个_count变量,下划线表明它是一个私有变量。再Javascript中下划线并没有什么实际的意义,但是它是一个用来标明私有变量的普遍用法。现在函数就可以操纵、返回变量了:

然而,你注意到了我吧整个库包含在了一个自调用匿名函数中。这是一个在执行过程中马上被执行的函数。这个函数运行,定义了函数和变量然后到了return {}的部分,它告诉函数将其返回给变量jspy,或者换句话说,暴露给用户。我们暴露两个函数而不是_count变量,这意味着我们可以做如下操作:

jspy.incrementCount();
jspy.getCount();

但是当我们试图进行如下操作时:

jspy._count; //undefined

它返回undefined。

对于上面的这种设计模式有许多不同的实现方法。有人喜欢在return 中定义函数:

var jspy = (function() {
    var _count = 0;

    return {
      incrementCount: function() {
        _count++;
      },
      getCount: function() {
        return _count;
      }
    };
})();   

受到上面例子的启发,CHristian Heilmann提出了Revealing Module Pattern。他的方法是将所有方法定义为私有变量,也就是说,不在return中定义,但是在那里暴露给用户,如下所示:

var jspy = (function() {
  var _count = 0;
  var incrementCount = function() {
    _count++;
  };
  var resetCount = function() {
    _count = 0;
  };
  var getCount = function() {
    return _count;
  };
  return {
    add: incrementCount,
    reset: resetCount,
    get: getCount
  };
})();

这种设计模式有两个好处:

  • 首先,它使我们更容易的了解暴露的函数。当你不在return中定义函数时,我们能轻松的了解到每一行就是一个暴露的函数,这时我们阅读代码更加轻松。

  • 其次,你可以用简短的名字(例如 add)来暴露函数,但在定义的时候仍然可以使用冗余的定义方法(例如 incrementCount)。

相关阅读:阮一峰:Javascript模块化编程(一):模块的写法