JSでパブリックメソッドを作るときの作法
以下はJavaScriptでよく使われるプライベート変数とパブリックメソッドの作り方である。
var glbVar = (function () { var privVar; return { publMethod: function () {} }; }());
これは以下のようにも書き直せる。
var glbVar = (function () { var privVar, //一旦変数に格納 obj = { publMethod: function () {} }; return obj; }());
どちらも結果は同じで、最初の例の方が無駄な変数宣言もなく、スマートに思える。なので私自身ずっと前者でコードを書いてきたのだが、つい最近、この前者と後者、大きく違う部分があることに気がついた。
publMethodを以下のようにして考えよう。
{ publMethod: function () { this.publAnotherMethod(); }, //別のパブリックメソッド publAnotherMethod: function () {} }
publMethodはコンテキストthisを介し、別のパブリックメソッドを呼んでいる。もちろんどちらもパブリックメソッドであるため、glbVar経由で別のメソッドを呼ぶこともできるが、グローバル参照は低速であるため、可能であればさけるべきというのが習わしだ。
これは何の問題もなく動作する。しかし、仮に以下のような方法でpublMethodが呼び出された場合、問題が起きる。
glbVar.publMethod.call(this, someCallBackFunc);
コンテキストの書き換え。特にpublMethodがコールバック関数を用いる場合、上記のような呼び出しは多いにあり得る。この場合、this.publAnotherMethod は undefinedとなり、JSの実行は停止するだろう。
つまり、コンテキストに依存したソースはさけるべきであり、最初の二つの例の後者、一旦変数にパブリックメソッドを格納する方法をとるべきだということである。
var glbVar = (function () { var privVar, //一旦変数に格納 obj = { publMethod: function () { //obj経由で他のパブリックメソッドにアクセスする obj.publAnotherMethod(); }, //別のパブリックメソッド publAnotherMethod: function () {} }; return obj; }());
JSでは気軽にコンテキストを書き換えられるため(またイベントハンドラの仕様おかげでそうせざるを得ない状況が多々あることで)、ライブラリ開発や共通関数の作成で特に考慮すべきことである。