Home >Web Front-end >JS Tutorial >JS attribute characteristics (property descriptor)
JS attribute characteristics (property descriptor)
ECMAScript 5 defines an object called "property descriptor", which is used to describe various characteristics. "Property Descriptor" objects can only be used in Object.defineProperty or Object.defineProperties.
Concept
ECMAScript 5 defines an object called "property descriptor", which is used to describe various characteristics. The attribute descriptor object has 4 attributes:
configurable: Configurability, which controls the modification of the attribute it describes, indicating whether the characteristics of the attribute can be modified, whether the attribute can be modified into an accessor attribute, or whether it can be deleted through delete Properties thereby redefining properties. The default value is true.
enumerable: Enumerability, indicating whether attributes can be obtained through for-in traversal. The default value is true.
writable: Writability, indicating whether the value of the attribute can be modified. The default value is true.
value: Data attribute, indicating the value of the attribute. The default value is undefined.
In addition to the above attributes, there are two accessor attributes, namely get and set, which can replace value and writable.
get: Function called when reading attributes. Specifying only get means that the attribute is read-only. The default value is undefined.
set: Function called when writing properties. Specifying only set means that the attribute is a write-only attribute. The default value is undefined.
Using
"Property Descriptor" objects can only be used in Object.defineProperty or Object.defineProperties.
API Usage
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 } } })
When using Object.defineProperty or Object .defineProperties will throw a type error exception when operating (creating or modifying) properties that are not allowed to be created or modified.
// 此例子运行在前面的例子的基础上 Object.defineProperty(hello, 'boy', { writable: true }) // Uncaught TypeError: Cannot redefine property: boy
Because the boy attribute has been set to non-configurable previously, modifying writable here will throw a type error exception.
Property descriptors can be obtained through Object.getOwnPropertyDescriptor or Object.getOwnPropertyDescriptors.
API Usage
Object.getOwnPropertyDscriptor: https://developer.mozilla.org...
Object.getOwnPropertyDescriptors: https://developer.mozilla.org...
Rules
var rules = { common: 'test' }
If the property is not available Configurable, its configurability and enumerability cannot be modified.
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}
If the accessor property is non-configurable, the get and set methods cannot be modified, nor can it be converted to a data property.
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
If a data property is non-configurable, it cannot be converted into an accessor property; at the same time, its writability cannot be modified from false to true, but it can be modified from true to 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}
If the data attribute is non-configurable and non-writable, its value cannot be modified; if it is configurable but not writable, its value can be modified (actually mark it as writable first and then modify it its value and finally mark it back as unwritable).
In fact, the modified value mentioned here is modified through the Object.defineProperty or Object.defineProperties method. If the data attribute is not configurable, the attribute value cannot be modified through direct assignment.
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'
Only specifying set cannot be read. If you try to read the attribute value, undefined will be returned. (The Red Book says that an exception is only thrown in strict mode, but it doesn’t)
Object.defineProperty(rules, 'rule7', { get: function() { return this.common } }) rules.rule7 = 'rule7' // Uncaught TypeError: Cannot redefine property: rule7
If the object is not extensible, you can edit the existing own properties, but you cannot add new properties to it.
There are three APIs for operating object extensibility: Object.preventExtensions, Object.seal, and Object.freeze.
API Usage
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...
Use Object.preventExtensions to convert objects to non-extensible.
Use Object.isExtensions to determine whether an object is extendable.
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.
In addition to converting the object to non-extensible, using Object.seal can also convert all of the object's own properties to non-configurable. That is, new attributes cannot be added to the object, and its existing attributes cannot be deleted or configured (the same rules as before will be followed here).
Use Object.isSealed to determine whether the object is sealed.
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.
Using Object.freeze, in addition to converting an object to non-extensible and its properties to non-configurable, you can also convert your own properties to read-only. (If the object is set, the accessor properties will not be affected, and the set method can still be called, and no exception will be thrown, but if the set method changes the properties of the object, it cannot be modified successfully)
Use Object .isFrozen to detect whether the object is frozen.
var fr = {} Object.defineProperty(fr, 'fr1', { configurable: true, writable: false, value: 'fr1' }) Object.isFrozen(fr) // false Object.freeze(fr) Object.isFrozen(fr) // true // 修改已有的属性会抛出类型错误异常 Object.defineProperty(fr, 'fr1', { writable: true, value: 'fr11' }) // Uncaught TypeError: Cannot redefine property: fr1 // 添加属性会抛出类型错误异常 Object.defineProperty(fr, 'fr2', { value: 'fr2' }) // Uncaught TypeError: Cannot define property:fr2, object is not extensible. fr.fr1 = 'fr11' // 不能修fr1属性 fr.fr1 // 'fr1' var set = {} Object.defineProperty(set, 'set1', { configurable: true, value: 'set1' }) Object.defineProperty(set, 'set2', { configurable: true, set: function(val) { this.set1 = val } }) Object.isFrozen(set) // false Object.freeze(set) Object.isFrozen(set) // true set.set2 = 'set2' set.set1 // 'set1'
Epilogue
I am very unfamiliar with attribute descriptors, mainly because I rarely use them. However, recently, I started to learn to write some small libraries (although it was very frustrating), and I felt that there are scenarios for using attribute descriptors. What I can think of for the time being is to set some properties of the library object to read-only to prevent some properties of the object from being overwritten by users. There is another usage that I learned when I was learning Vue on Zhihu, which is to use getters and setters to "monitor" the data updates of object properties