モジュールパターン

Last Change:22-May-2016.
Author:qh73xe

./1.class.rst では JS におけるクラスの実装を考えていきました。 今回はモジュールの実装を行っていきます。

モジュールパターンはオブジェクトリテラルに部分的に基づいているので、 まずはオブジェクトリテラルに関して見ていきます。

オブジェクトリテラル

オブジェクトリテラル表記とは、 ようはオブジェクトを記述する方法の一つで、 以下の書き方を行います。

objectliteral.js
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
var myMojule = {
  myProperty: "hoge",
  myConf: {
    useCaching: true,
    language: "ja"
  },
  myMethod: function(){
    return "hogehoge";
  },
  myMethod2: function(){
    return "The language is " + this.myConf.language;
  },
  myMethod3: function(newConf){
    if(typeof newConf == "object"){
      this.myConf = newConf;
      text = this.myMethod2();
      return text;
    }
  },
};

// use myMethod
r1 = myMojule.myMethod();
r2 = myMojule.myMethod2();
r3 = myMojule.myMethod3({
  language: "en",
  useCaching: true
});

print(r1);
print(r2);
print(r3);

上記のようにオブジェクトリテラルを使用することでコードをカプセル化することができます。 myMojule.myConf に関して、これを直接書き換える方法を取っていないことに注意してください。

モジュールパターン

上記に示したようにモジュール化の本質は、 結局の所 クラスに パブリックとプライベート両方のカプセル化 を行うことです。

JS の場合, ./1.class.rst でも記述したとおり クラスの概念を持たないため、これを模倣する方法が必要です。 この方法として使用できるパターンがモジュールパターンです。 このパターンを利用することで、一つのオブジェクトにパブリックとプライベートなメゾット及び変数を定義でき、 グローバルな空間での使用を防ぐことができます。

このようにグローバルな空間とプライベートな空間を分けておくことで、 例えば、自分の作成した関数、変数名と、別の人間が作成した関数、変数名が類似あるいは衝突することを防ぎやすくなります。

プライバシー

モジュールパターンではクロージャーを使用して、 プライバシー な状態と構成をカプセル化します。 つまり、このパターンを使用することで、外部に公開された API だけが値を返し、それ以外については全て外部から操作することはできなくなります。

注釈

外部/内部

とくにプログラミングに慣れていない間は外部とか内部といった用語にイメージが沸きにくいかも知れません。

  • 私の場合、単純にファイル単位で考えていたこともあります。(恥ずかしい思い出ですが)

あまり厳密なことにこだわらないざっくりとした説明をすれば、 ここでいう外部/内部とは、例えば一つのクラスの処理の中と外と思えばよいです。 クラスの宣言をしている部分が内部で、クラスの処理を実際に書いている場所が外部です。

  • パブリック、プライベートといっている語も同じイメージでよいです。

ここで JS 特有の仕様で、厳密にはパブリック、プライベート両方の変数を明示的に宣言することができません。 その代わりとして、関数のスコープを利用します。

実装

概念的な説明はここまでにして実際に簡単なモジュールを作成してみましょう。 ここでは極めて単純なカウンターを作成します。

mojule.js
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
var testModule = (function () {
  // プライベート
  var counter = 0;

  // パブリック
  return {
    countInc: function(){
      return ++ counter;
    },
    countReset: function(){
      counter = 0;
    },
    show: function(){
      return "count is " + counter;
    }
  };
})();

testModule.countInc();

print(testModule.show());
print(testModule.counter);  // counter に直接アクセスができない

testModule.countReset();
print(testModule.show());

このスクリプトでは外部に countInc, countReset, show の三つの関数を公開しています。 一方で 変数 counter はプライベートな変数です。

この効果が分かるのが、強調を行った、 21, 22 行目の比較です。 早速上記スクリプトを実行してみましょう。

$ js mojule.js
count is 1
undefined
count is 0

前者は公開されている show 関数を利用しているので、 counter の値がわかります。 しかし、後者の方では直接プライベートな変数にアクセスしようとしているため、 値が隠蔽されています。