プロパティ記述子は、ES5 の新しい概念であり、その機能はオブジェクトのプロパティにさらなる制御を追加することです。
Object.defineProperty
プロパティ記述子について学ぶには、まず Object.defineProperty メソッドについて説明する必要があります。このメソッドの目的は、オブジェクトの新しいプロパティを定義するか、既存のプロパティを変更することです。そのプロトタイプは次のとおりです:
Object.defineProperty(obj, prop, descriptor)
使用例:
var obj = { };
Object.defineProperty(obj, 'attr', { value: 1 });
上記のコードは、値 1 を持つ attr という名前の属性を obj オブジェクトに追加します。以下と同等:
var obj = { };
obj.attr = 1;
それに比べて、Object.definePropertyの書き方は複雑なようです。ただし、最大の秘密は 3 番目のパラメータにあります。
データ記述子
attr を読み取り専用属性にしたいとすると、書き込み可能なデータ記述子を追加できます:
var obj = { };
Object.defineProperty(obj, 'attr', {
値: 1、
書き込み可能: false
});
console.log(obj.attr);
obj.attr = 2 // 失敗します
console.log(obj.attr);
上記プログラムを実行すると、2回出力されたattrの値が1となっており、属性の書き込みに失敗していることがわかります。ただし、代入ステートメントが例外なく実行に失敗したため、このような結果は少し不可解になります。大規模なコードでそのような問題が発生した場合、トラブルシューティングが困難になることを想像してください。実際、厳密モードでコードを実行するだけで例外が発生します:
'use strict' // strict モードに入ります
var obj = { };
Object.defineProperty(obj, 'attr', {
値: 1、
書き込み可能: false
});
obj.attr = 2 // 例外をスローします
プロパティを列挙できるかどうかを制御できる、別の列挙可能なデータ記述子を見てみましょう。単に属性を定義する場合、この属性は for...in ループで列挙できます:
var obj = { };
obj.attr = 1;
for (obj の変数 i) { console.log(obj[i]) }
enumerable はそれを「隠す」ことができます:
var obj = { };
Object.defineProperty(obj, 'attr', {
値: 1、
列挙可能: false
});
for (obj の変数 i) { console.log(obj[i]) }
上記のコードを実行すると、現時点では attr 属性を列挙できないため、コンソールには何も出力されないことがわかります。
この時点で、属性記述子は変更できるのかという質問があるかもしれません。たとえば、読み取り専用プロパティを再度書き込み可能として定義できますか?実際、これは、プロパティ記述子を変更できるかどうかを制御する、構成可能な別のデータ記述子に依存します。
var obj = { };
Object.defineProperty(obj, 'attr', {
値: 1、
書き込み可能: false、
構成可能: true
});
Object.defineProperty(obj, 'attr', {
書き込み可能: true
});
obj.attr = 2;
上記のコードは、最初に attr を読み取り専用属性として定義し、次にそれを書き込み可能属性として再定義します。したがって、attr への書き込みは成功します。
アクセス記述子
アクセス記述子は、オブジェクト指向の get/set アクセサーに似ています。
var obj = { };
Object.defineProperty(obj, 'attr', {
set: function(val) { this._attr = Math.max(0, val) },
;
取得: function() { return this._attr }
});
obj.attr = -1;
console.log(obj.attr); // 0
上記のコードでは、attr へのアクセスは実際には _attr へのアクセスとなり、set 関数の最小値は 0 に制限されています。
属性記述子の取得
上記はすべて属性記述子の設定に関するものですが、設定された記述子を取得するにはどうすればよいでしょうか? Object.getOwnPropertyDescriptor がその役割を果たします。
var obj = { };
Object.defineProperty(obj, 'attr', {
値: 1、
書き込み可能: false、
構成可能: true
});
var desc = Object.getOwnPropertyDescriptor(obj, 'attr');
console.dir(desc);
オブジェクト コントロール
前述の Object.defineProperty はオブジェクトのプロパティを操作しますが、以下で説明する 3 つのメソッドはオブジェクトを直接操作します。
Object.preventExtensions は、オブジェクトが新しいプロパティを持たないようにすることができます:
var obj = { };
obj.attr = 1;
Object.preventExtensions(obj);
obj.attr2 = 2 //失敗
Object.seal は、オブジェクトに変更可能な属性値のみを持たせることができます (属性が読み取り専用の場合、属性値も変更できません):
var obj = { };
obj.attr = 1;
Object.seal(obj);
obj.attr = 1.5;
obj.attr を削除します。 // 失敗します
Object.freeze により、オブジェクトを完全に変更不能にすることができます:
var obj = { };
obj.attr = 1;
Object.freeze(obj);
obj.attr = 1.5 // 失敗します
obj.attr2 = 2 //失敗
次に、オブジェクトが拡張機能、封印されているか、または凍結されているかどうかをどのようにして知ることができるのかと疑問に思われるかもしれません。答えは、Object.isExtensible、Object.isSealed、Object.isFrozen をそれぞれ呼び出すことです。これら 3 つの関数の使用法は比較的簡単で、面倒なことはありません。
一般に、オブジェクトは属性記述子によってさらに厳密に制御でき、プログラム ロジックの厳密性を強化できます。唯一の欠点は、ES5 が基本的に IE9 でしか実装されていないことです (国内向けであることを考慮すると、IE9 はまだ厳密モードをサポートしていません)。 IE8 シェアはまだ比較的高いですが、このセットは現在モバイル ブラウザーと Node.js でのみ使用できます。