JS属性特性(プロパティ記述子)
ECMAScript 5では、さまざまな特性を記述するために使用される「プロパティ記述子」と呼ばれるオブジェクトが定義されています。 「プロパティ記述子」オブジェクトは、Object.defineProperty または Object.defineProperties でのみ使用できます。
Concept
ECMAScript 5 では、さまざまな特性を記述するために使用される「プロパティ記述子」と呼ばれるオブジェクトが定義されています。属性記述子オブジェクトには 4 つの属性があります:
configurable: 構成可能性。記述された属性の変更を制御し、属性の特性を変更できるかどうか、属性をアクセサー属性に変更できるかどうかを示します。プロパティの削除によって削除されるため、プロパティが再定義されます。デフォルト値は true です。
enumerable: 列挙可能性。for-in トラバーサルを通じて属性を取得できるかどうかを示します。デフォルト値は true です。
writable: 属性の値を変更できるかどうかを示す書き込み可能性。デフォルト値は true です。
value: データ属性。属性の値を示します。デフォルト値は未定義です。
上記の属性に加えて、get と set という 2 つのアクセサー属性があり、値と書き込み可能を置き換えることができます。
get: 属性を読み取るときに呼び出される関数。 get のみを指定すると、属性は読み取り専用になります。デフォルト値は未定義です。
set: プロパティの書き込み時に呼び出される関数。 set のみを指定すると、その属性は書き込み専用属性になります。デフォルト値は未定義です。
使用方法
「プロパティ記述子」オブジェクトは、Object.defineProperty または Object.defineProperties でのみ使用できます。
APIの使用法
Object.defineProperty: https://developer.mozilla.org...
Object.defineProperties: https://developer.mozilla.org...
var hello = {} Object.defineProperty(hello, 'girl', { configurable: false, enumberable: false, writable: true, value: 'sexy' }) // 存取器 Object.defineProperty(hello, 'woman', { configurable: false, enumberable: false, get: function() { return this.girl }, set: function(val) { this.girl = val } }) // 定义多个属性 Object.defineProperties(hello, { boy: { configurable: false, enumberable: false, writable: false, value: 'handsome' }, man: { configurable: false, enumberable: false, writable: true, get: function() { return this.boy } } })
Object.definePropertyまたはObjectを使用する場合.defineProperties は、作成または変更が許可されていないプロパティを操作 (作成または変更) する場合、型エラー例外をスローします。
// 此例子运行在前面的例子的基础上 Object.defineProperty(hello, 'boy', { writable: true }) // Uncaught TypeError: Cannot redefine property: boy
boy 属性は以前に設定不可に設定されているため、ここで writable を変更すると型エラー例外がスローされます。
プロパティ記述子は、Object.getOwnPropertyDescriptor または Object.getOwnPropertyDescriptors を通じて取得できます。
API の使用法
Object.getOwnPropertyDscriptor: https://developer.mozilla.org...
Object.getOwnPropertyDescriptors: https://developer.mozilla.org...
ルール
var rules = { common: 'test' }
プロパティが利用できません 構成可能ですが、その構成可能性と列挙可能性は変更できません。
Object.defineProperty(rules, 'rule1', { configurable: false, enumberable: false }) // 修改configurable会抛出类型错误异常 Object.defineProperty(rules, 'rule1', { configurable: true }) // Uncaught TypeError: Cannot redefine property: rule1 // 修改enumberable不会抛出异常,但enmuberable没有被修改 Object.defineProperty(rules, 'rule1', { enumberable: true }) Object.getOwnPropertyDescriptor(rules, 'rule1') // Object {value: undefined, writable: false, enumerable: false, configurable: false}
アクセサー プロパティが構成不可能な場合、get メソッドと set メソッドを変更したり、データ プロパティに変換したりすることはできません。
Object.defineProperty(rules, 'rule2', { configurable: false, enumberable: false, get: function() { return this.common }, set: function(val) { this.common = val } }) // 修改get或者set方法会抛出类型错误异常 Object.defineProperty(rules, 'rule2', { get: function() { return this.common + 'rule2' } }) // Uncaught TypeError: Cannot redefine property: rule2 Object.defineProperty(rules, 'rule2', { set: function(val) { this.common = 'rule2' } }) // Uncaught TypeError: Cannot redefine property: rule2 // 将它转换为数据属性同样会抛出类型错误异常 Object.defineProperty(rules, 'rule2', { value: 'rule2' }) // Uncaught TypeError: Cannot redefine property: rule2
データ プロパティが構成不可能な場合、アクセサー プロパティに変換することはできません。同時に、その書き込み可能性を false から true に変更することはできませんが、true から false に変更することはできます。
Object.defineProperty(rules, 'rule3', { configurable: false, writable: false, value: 'rule3' }) // 修改writable为true会抛出类型错误异常 Object.defineProperty(rules, 'rule3', { writable: true }) Object.defineProperty(rules, 'rule4', { configurable: false, writable: true, value: 'rule4' }) // 可以修改writable为false Object.defineProperty(rules, 'rule4', { writable: false }) Object.getOwnPropertyDescriptor(rules, 'rule4') // Object {value: "rule4", writable: false, enumerable: false, configurable: false}
データ属性が構成不可かつ書き込み不可の場合、その値は変更できません。構成可能だが書き込み不可の場合、その値は変更できます (実際には、最初に書き込み可能としてマークし、次にその値を変更し、最後にその値を変更します)書き込み不可としてマークを付け直します)。
実際、ここで言及されている変更された値は、Object.defineProperty または Object.defineProperties メソッドを通じて変更されます。データ属性が構成可能でない場合、直接割り当てを通じて属性値を変更することはできません。
Object.defineProperty(rules, 'rule5', { configurable: false, writable: false, value: 'rule5' }) // 修改属性值会抛出类型错误异常 Object.defineProperty(rules, 'rule5', { value: 'rule55' }) // Uncaught TypeError: Cannot redefine property: rule5 rules.rule5 = 'rule55' // 值没有被修改,也不会抛出异常 rules.rule5 // 'rule5' Object.defineProperty(rules, 'rule6', { configurable: true, writable: false, value: 'rule6' }) // 修改属性值 Object.defineProperty(rules, 'rule6', { value: 'rule66' }) rules.rule6 // 'rule66' rules.rule6 = 'rule6' // 值没有被修改,也不会修改 rules.rule6 // 'rule6'
setを指定しただけではプロパティの値を読み込めません。 (レッドブックには、例外は厳密モードでのみスローされると書かれていますが、そうではありません)
Object.defineProperty(rules, 'rule7', { get: function() { return this.common } }) rules.rule7 = 'rule7' // Uncaught TypeError: Cannot redefine property: rule7
オブジェクトが拡張可能でない場合、既存の独自のプロパティを編集することはできますが、それに新しいプロパティを追加することはできません。
オブジェクトの拡張性を操作するための API は、Object.preventExtensions、Object.seal、Object.freeze の 3 つです。
API の使用法
Object.preventExtensions: https://developer.mozilla.org...
Object.seal: https://developer.mozilla.org...
Object.freeze: https:// developer.mozilla.org...
Object.isExtensions: https://developer.mozilla.org...
Object.isSealed: https://developer.mozilla.org...
Object.isFrozen: https://developer.mozilla.org...
オブジェクトを拡張不可能に変換するには、Object.preventExtensions を使用します。
Object.isExtensions を使用して、オブジェクトが拡張可能かどうかを判断します。
var ex = {} Object.defineProperty(ex, 'ex1', { configurable: true, writable: true, value: 'ex1' }) Object.isExtensible(ex) // true Object.preventExtensions(ex) Object.isExtensible(ex) // false // 可以修改已有的属性 Object.defineProperty(ex, 'ex1', { writable: false, value: 'ex11' }) Object.getOwnPropertyDescriptor(ex, 'ex1') // Object {value: "ex11", writable: false, enumerable: false, configurable: true} // 添加属性会抛出类型错误异常 Object.defineProperty(ex, 'ex2', { value: 'ex2' }) // Uncaught TypeError: Cannot define property:ex2, object is not extensible.
オブジェクトを拡張不可に変換するだけでなく、Object.seal を使用すると、オブジェクト自体のプロパティをすべて構成不可に変換することもできます。つまり、新しい属性をオブジェクトに追加したり、既存の属性を削除したり構成したりすることはできません (ここでも以前と同じルールに従います)。
オブジェクトがシールされているかどうかを判断するには、Object.isSealed を使用します。
var se = {} Object.defineProperty(se, 'se1', { configurable: true, writable: false, value: 'se1' }) Object.isSealed(se) // false Object.seal(se) Object.isSealed(se) // true // 修改已有的属性会抛出类型错误异常 Object.defineProperty(se, 'se1', { writable: true, value: 'se11' }) // Uncaught TypeError: Cannot redefine property: se1 // 添加属性会抛出类型错误异常 Object.defineProperty(se, 'se2', { value: 'se2' }) // Uncaught TypeError: Cannot define property:se2, object is not extensible.
Object.freeze を使用すると、オブジェクトを拡張不可に変換し、そのプロパティを構成不可能に変換するだけでなく、独自のプロパティを読み取り専用に変換することもできます。 (オブジェクトが設定されている場合、アクセサーのプロパティは影響を受けず、set メソッドを引き続き呼び出すことができ、例外はスローされませんが、set メソッドがオブジェクトのプロパティを変更すると、正常に変更できなくなります)
Object .isFrozen を使用して、オブジェクトがフリーズしているかどうかを検出します。
えーエピローグ
属性記述子をほとんど使用しないため、属性記述子についてはあまり詳しくありません。しかし、最近、いくつかの小さなライブラリを書くことを学び始めました (非常にイライラしましたが)、属性記述子を使用するシナリオがあると感じました。当面考えられるのは、ライブラリ オブジェクトの一部のプロパティを読み取り専用に設定して、オブジェクトの一部のプロパティがユーザーによって上書きされないようにすることです。 Zhihu で Vue を学習していたときに学んだもう 1 つの使用法があります。それは、ゲッターとセッターを使用してオブジェクト プロパティのデータ更新を「監視」することです