ブログネタ
JavaScript に参加中!

友人に聞かれた内容のメモ。JavaScriptでは一般的な使い方なのですが、privateやpublicで指定できないので、初めのうちは結構戸惑いますね。

共有変数・関数をオブジェクトのプロパティ・メソッドで作る

まず、共有プロパティを使ったメソッドが存在するオブジェクトを普通に作ってみます。

var obj = {
  // 内部で使うための共有プロパティ
  prop0: 0,
  
  // 内部で使うための共有メソッド
  method0: function() {
    return ++this.prop0;
  },
  
  // 外部から使うためのメソッド
  method1: function() {
    alert(this.method0());
  }
}

obj.method1();	// 1と表示
obj.method1();	// 2と表示

ただし、prop0やmethod0は内部だけで使いたいのに、外部からもアクセスできてしまいます。
↓上からの続き

obj.prop0++;	// 外部から値を変えられたり
obj.method0();	// 外部から実行されたり

純粋に内部で使うための変数や関数を外部に見せてしまうのは良くないですね。JSの場合は特にメソッドのオーバーライドができてしまうから何かとトラブルの元。

obj.method0 = 'foo';	// 外部からオーバーライドされたりする
obj.method1();		// this.method0 is not a function

オブジェクトのプロパティやメソッドは外部での使用に限るに越したことはありません。

プライベート変数・関数

functionで一段スコープを下げるだけで簡単にプライベート変数を実現できます。
オブジェクトのプライベート変数はエンクロージャの内部変数(つまりオブジェクトの外)で作っておき、オブジェクト自身はエンクロージャからreturnで戻します。

// エンクロージャの戻り値(作成するオブジェクト)をobjに代入
var obj = function() {
  
  // オブジェクトで使うプライベート変数
  var prop0 = 0;

  // オブジェクトで使うプライベート関数
  var func0 = function() {
    return ++prop0;
  };

  // オブジェクト本体(objに返す)
  return {
    
    // 外部から使うメソッド1
    method1: function() {
      alert(func0());
    },

    // 外部から使うメソッド2
    method2: function() {
      func0();
      alert(func0());
    }
  };
}();	// ←カッコ()付きなので無名関数(エンクロージャ)が実行される

obj.method1();	// 1と表示
obj.method2();	// 3と表示
// ↑func0を通してprop0の値が保持されている証拠

method1はクロージャとして働きます。その中で使われるfunc0は無名関数実行後も保持されます(レキシカル関数)。

更にfunc0もクロージャなので、その中で使われるprop0も保持されます(レキシカル変数)。こういう工夫ってJSならではですね。

クロージャについてはまたの機会にでも。