JavaScriptでprototype継承を行う際、各インスタンスが内部的に保持しておきたいプロパティを、次のように外部から通常アクセスできないように隠蔽する方法があります。
これにより、他の実装者が手軽にオブジェクトの改変を行ってしまうことを防ぐことができます。
sample.js
(function(){
// 呼び出し元をチェックする関数.
// このオブジェクトにアクセス可能なスコープからしか、エラーが発生しない呼び出しをできない.
var chk = function(c) {
if (c !== chk) { throw new Error("illegal access.") }
return true
}
window.Sample = function() {
// 内部的なプロパティ
var pvt = {
count: 0,
}
// 内部的なプロパティを取得するメソッド.
// 引数にchkオブジェクトを渡さないといけない点がポイント.
this._p = function(c) { return chk(c) && pvt }
}
Sample.prototype.increment = function() {
this._p(chk).count++
}
})();
// 外部からの呼び出し
var sample = new Sample()
sample.increment() // ok
sample._p().count++ // error
-
ポイント
- 特定のスコープでしかアクセスできないオブジェクトを、メソッド呼び出しの認証のように使っています。
- 同様の方法でprivateメソッドの実装が可能です。
- ES2015以前の仕様でも実装可能です。
-
注意
- 当然ながら、オブジェクトの挙動を変更する方法は他にいくらでもあるため(上の例だと、window.Sampleそのものを上書きするなど)、あくまでプロパティを手軽にアクセスしたり、変更したりすることを防ぐための措置です。
- 対象オブジェクト(上の例だとnew Sample())をコンソール出力しても、隠蔽しているプロパティが表示されないため、デバッグに困ることがあります。
- prototypeを使う必要がなければ、privateなプロパティの実装はクロージャを使えば簡単に済みます。上記の手法はprototypeを定義しつつ、各インスタンスごとのprivateプロパティを保持する場合に役立ちます。