Data encapsulation in JavaScript: getters and setters
大規模な JavaScript アプリケーションを構築すると、すぐにそれを明確な契約によってリンクしたモジュールに分割する必要が出てくるものです。 長期的なメンテナンスに関して言えば、インターフェイスの変更時に互換性を維持する方法を提供する必要があります。 これを行うために、オブジェクト指向言語はカプセル化、またはコードの一部のユーザーから実装の詳細を隠す情報に依存しており、クライアントに影響を与えることなく変更することができます。 より具体的には、ゲッターとセッターの背後にあるプロパティのカプセル化について説明します。
いくつかの概念
JavaScriptは、アヒルの型付けの原則を基礎として設計されています。「しかし、C# や Java などの他のオブジェクト指向言語とは異なり、JavaScript ではクラスは二級市民であり、インターフェイスは存在しません。 オブジェクトには型がないため、特定のプロパティやメソッドを持つオブジェクトへのインターフェースをコードで記述する必要があります。 モジュール間の契約は、交換されたオブジェクトに存在すると想定される一連のメソッドおよびプロパティに基づいています。 これは、与えられたオブジェクトがその内部の動作の詳細を隠すことができ、それと相互作用する他のオブジェクトがその実装の詳細ではなく、高レベルで合意されたインタフェースに依存しないようにすることを意味する。 これは、クライアント オブジェクトを壊すことなく実装の詳細を変更できることをプロバイダー側とユーザー側の両方が知っているので、開発者の生活をよりシンプルにします。 メソッド間のインターフェイスは、クライアント コードがオブジェクト上で見つけることを期待するプロパティのセットです。
オブジェクトがメソッドのみを公開する場合、インターフェイスを時間と共に進化させることは簡単です。 メソッドはそのパラメータをチェックし、それに応じて反応することができます。 また、新しい機能を提供する新しいメソッドを作成することも可能です。 また、古いメソッドをサポートして、新しいメソッドに古い動作を適応させることもできます。
プロパティの場合、安定したインターフェイスを維持することは容易ではありません。 なぜなら、デフォルトで、クライアント コードはオブジェクトの存在しないプロパティを参照することができるからです。 存在しないプロパティに書き込むと、それが作成されます。 読み込むと未定義が返されます。 クライアントコードは、非推奨のプロパティを使用しているかどうかをすぐに検出することができない。 さらに悪いことに、エラーはコードの他の部分に伝播する可能性があり、問題の検出を難しくします。
The standard JavaScript API には、このような問題の回避に役立つ可能性のあるメソッドがあります:それは、非サポートのプロパティ名を使用できないようにオブジェクトをフリーズまたはシールすることが可能です。
Getter/Setters to save the day
メソッド実装の詳細を隠すのは簡単です。
Getters/setters は ECMAScript 5.1 (ECMA-262) で言語に正式に導入されました。 これらは現在、すべての主要なデスクトップおよびモバイル ブラウザでサポートされています。
基本的な考え方は、単純なデータ プロパティの代わりに、メソッドとしてアクセッサ プロパティを定義する構文を追加することです。 ゲッターは、キーワード get の後に、引数を取らずプロパティの値を返す、プロパティにちなんで名付けられた関数で定義されます。 セッターは、キーワード set の後に、プロパティの新しい値を引数として取る、プロパティの名前の付いた関数を続けることで定義されます。
次の例は、prop というアクセッサ プロパティを定義するために使用されるゲッターとセッターを示しています:
var obj = { v: 0, get prop() { return this.v; }, set prop(newValue) { this.v = newValue; }};console.log(obj.prop);obj.prop = 42;console.log(obj.prop);
出力:
042
セッターなしでゲッターを定義して、読み取り専用のプロパティを作成することもできます。
var obj = { get prop() { return -1; },};console.log(obj.prop);obj.prop = 42;console.log(obj.prop);
Output:
-1-1
プロパティは、クラスの実装が変更された場合に、それに反応し、クラスの動作を適応させることができるいくつかのメソッドに置き換えることができます。 最悪の場合、プロパティが非推奨であり、もう使用すべきではないことをユーザーに伝えるために例外を発生させることができます。
Further reading
この投稿で、JavaScript で複雑な進化型アプリケーションを設計することについて何か新しく学んでいただければ幸いです。 このセクションでは、より多くの情報を含むリンクへのいくつかのリンクを提供します。
Introductory articles
このセクションでは、概念を提示し、関連する API の概要を提供する短い記事をいくつか紹介します。
More advanced articles
The these articles talk about more advanced related topics like the problems brought by getters and setters, and how to solve them.
- Why getters/setters is a bad idea in JavaScript
- Data encapsulation in JavaScript
Reference documentation
最後に、この話題を本当にマスターするには、関連 API のモジラ文書へのリンク:
- get と set によってゲッターとセッターが定義されるようになりました。 ここで説明したこと以外にも 動的に生成されるプロパティ名のサポートや、配列の値の設定/取得をシミュレートするためにゲッターとセッターを使用するなど、他にも興味深い機能があります
- seal と freeze は、オブジェクトのどのプロパティが変更可能かどうか、そしてどのように変更するかを制御することを可能にします。 これは、クライアントがオブジェクトの API の非推奨の部分を使用することを避けるために使用できます。
- defineProperty は、ゲッターとセッターを定義すると同時に、これらのプロパティがクライアントによってどのように見られ、どのように変更可能かをより制御することができます。