問題にはいくつかのアプローチがあり、どのアプローチを選択するかは、(1) ターゲット ブラウザーのサポート、(2) プロジェクトの目標、(3) 個人の好みなど、いくつかの要因によって異なります。特に私が意見を持っているいくつかのアプローチを強調します。
シンボル
これは最も堅牢なソリューションであり、JavaScript の未来であるため、最初に強調します。これは、ECMAScript 標準の次のバージョンに含まれる予定です。現在、ES5 準拠のブラウザーでシムを使用することで可能です。つまり、基本的に過去 2 年間にリリースされたすべての A グレードのブラウザーで動作します。主な欠点は、IE 8 ではサポートされていないことですが、IE 9 および 10 (もちろん、FF、Chrome、および Safari のすべての最新バージョン) ではサポートされています。IE8 がまだ重要な場合、これはまだ選択肢ではありません。
シムはここからダウンロードできます: SymbolsForES5。このライブラリを使用すると、この機能を使い始めることができます。将来、Symbol がブラウザーにネイティブに組み込まれると、コードはうまく移行できるはずです。
プライベート メンバーにシンボルを使用する例を次に示します。
var x = { };
var a = new Symbol();
x[a] = 5;
console.log(x[a]); // => 5
a
Symbol オブジェクトにアクセスできる限り、x
オブジェクトからプロパティを読み取ることができますが、アクセス権のない人a
は読み取ることができません。これにより、実際にプライベートメンバーを持つことができます:
var Person = (function() {
var firstName = new Symbol(),
lastName = new Symbol();
function Person(first, last) {
this[firstName] = first;
this[lastName] = last;
}
Person.prototype.getFullName = function() {
return this[firstName] + ' ' + this[lastName];
};
return Person;
})();
var john = new Person('John', 'Smith');
john.getFullName(); // => 'John Smith'
Object.getOwnPropertyNames(john); // => [ ]
DON'T ACCESS文字の使用
あなたが言及したように、いつでもプロパティの前に文字 (アンダースコアなど) を付けて、外部コードからアクセスしてはならないことを示すことができます。主な欠点は、プロパティがまだアクセス可能であることです。ただし、いくつかの利点があります。(1)効率的なメモリ(2)プロトタイプの継承を使用する完全な機能(3)使いやすい(4)デバッグが容易 (プロパティがデバッガーに表示されるため) (5)すべてで動作するブラウザ。
私は過去にこの方法を広範囲に使用して大きな成功を収めました。アンダースコアの代わりに、私が開発した 1 つのフレームワーク (joi)で、シンボルを使用しまし#
た。これは、プロパティにアクセスするのが難しくなるためです (代わりに角括弧表記でアクセスする必要があります)。アクセスして、おそらくそのままにしておく必要があります。
function Person(first, last) {
this['#firstName'] = first;
this['#lastName'] = last;
}
Person.prototype.getFullName = function() {
return this['#firstName'] + ' ' + this['#lastName'];
};
var john = new Person('John', 'Smith');
john.getFullName(); // => 'John Smith'
私はこの手法を約 7 年間使用して大きな成功を収めてきました。シンボルがニーズに合わない場合は、この手法を強くお勧めします。
コンストラクター内のプライベート
メモリ/パフォーマンス上の理由から、この手法を使用しないことにしたとおっしゃっていましたが、真のプライベートに近いものが必要で、レガシー ブラウザのサポートが必要なためにシンボルを使用できない場合は、良いオプションです。私が勤務している会社では、大規模なアプリケーションでこのモデルを使用していますが、消費されるメモリは実際には問題になりません。さらに、このモデルでメモリとパフォーマンスを最適化する方法を発見した研究について聞いたことがあります。最新のブラウザー (他のブラウザーではないにしても、少なくとも V8/Chrome) はこれらの最適化を実装し始めていると思います。(この情報は、ブレンダン・アイクから聞いた話から得たものです。申し訳ありませんが、どの話が私の頭から離れたものだったのかわかりません。)
最終的に、この手法の使用を支持する専門家がいます。私の好みではありませんが、私の会社はこの手法で成功しており、信頼できるモデルであることを保証できます。
完全を期すために、次のようになります。
function Person(first, last) {
this.getFullName = function() {
return first + ' ' + last;
};
}
var john = new Person('John', 'Smith');
john.getFullName(); // => 'John Smith'
JavaScript エンジンは、メソッドごとに実際には新しい関数を作成しないことでこれを最適化することができますgetFullName
(本によると、作成することになっていますが)。この場合、毎回新しい関数オブジェクトを実際に作成するかどうかを判断する方法がないためです。厄介な部分は、新しい関数オブジェクトが作成されるたびに決定できるコードが導入されると、実際にそれを行うためにエンジンを切り替える必要があることです。
ウィークマップ
別の回答では、ベンビー( WeakMapsについて言及)[http://stackoverflow.com/a/12955077/1662998]。IE8 のサポートが必要で、プロパティで実際にプライベート メンバーをシミュレートする場合は、この代替手段も検討します。