Attribute descriptor is a new concept added in ES5, and its function is to add more control to the object's properties.
Object.defineProperty
To study attribute descriptors, we must first talk about the Object.defineProperty method. The purpose of this method is to define new properties for the object or modify existing properties. The prototype is as follows:
The code copy is as follows:
Object.defineProperty(obj, prop, descriptor)
Example of usage:
The code copy is as follows:
var obj = { };
Object.defineProperty(obj, 'attr', { value: 1 });
The above code adds an attribute named attr to the obj object, with a value of 1. Equivalent to:
The code copy is as follows:
var obj = { };
obj.attr = 1;
In comparison, the writing of Object.defineProperty seems to be more complicated. However, its biggest secret lies in its third parameter.
Data descriptor
Assuming that we want attr to be a read-only attribute, we can add the writable data descriptor:
The code copy is as follows:
var obj = { };
Object.defineProperty(obj, 'attr', {
value: 1,
writable: false
});
console.log(obj.attr);
obj.attr = 2; // fail
console.log(obj.attr);
Execute the above program and you will find that the value of attr printed out twice is 1, which means that the writing of the attribute failed. However, this result will be a bit inexplicable, because the execution of the assignment statement does not have any exceptions, but it fails. Just imagine that if such a problem occurs in the blockbuster code, it will be difficult to troubleshoot it. In fact, as long as the code is run in strict mode, an exception will be generated:
The code copy is as follows:
'use strict'; // Enter strict mode
var obj = { };
Object.defineProperty(obj, 'attr', {
value: 1,
writable: false
});
obj.attr = 2; // throw exception
Let’s take a look at another data descriptor enumerable, which can control whether the attribute can be enumerated. If you simply define a property, this property can be enumerated in the for...in loop:
The code copy is as follows:
var obj = { };
obj.attr = 1;
for (var i in obj) { console.log(obj[i]); }
enumerable can "hide" it:
var obj = { };
Object.defineProperty(obj, 'attr', {
value: 1,
enumerable: false
});
for (var i in obj) { console.log(obj[i]); }
Execute the above code and you will find that the console outputs nothing, because the attr attribute cannot be enumerated at this time.
Having said that, you may have a question: Can the attribute descriptor be modified? For example, can a read-only property be defined as writable again? Actually, this depends on another data descriptor configurable, which can control whether the attribute descriptor can be changed.
The code copy is as follows:
var obj = { };
Object.defineProperty(obj, 'attr', {
value: 1,
writable: false,
configurable: true
});
Object.defineProperty(obj, 'attr', {
writable: true
});
obj.attr = 2;
The above code first defines attr as a read-only attribute, and then redefines it as a writable. So the writing to attr is successful.
Access descriptor
The access descriptor is similar to the get/set accessor in object-oriented.
The code copy is as follows:
var obj = { };
Object.defineProperty(obj, 'attr', {
set: function(val) { this._attr = Math.max(0, val); },
get: function() { return this._attr; }
});
obj.attr = -1;
console.log(obj.attr); // 0
In the above code, access to attr actually becomes access to _attr, and the minimum value is limited to 0 in the set function.
Get attribute descriptor
The above mentioned are all setting attribute descriptors, so how to get the set descriptors? Object.getOwnPropertyDescriptor can do this.
The code copy is as follows:
var obj = { };
Object.defineProperty(obj, 'attr', {
value: 1,
writable: false,
configurable: true
});
var desc = Object.getOwnPropertyDescriptor(obj, 'attr');
console.dir(desc);
Object control
The Object.defineProperty mentioned earlier operates on the properties of the object, while the three methods mentioned below operate directly on the object.
Object.preventExtensions can prevent objects from having new properties:
The code copy is as follows:
var obj = { };
obj.attr = 1;
Object.preventExtensions(obj);
obj.attr2 = 2; //fail
Object.seal can make the object only property values left to modify (if the property is read-only, even the property values cannot be modified):
The code copy is as follows:
var obj = { };
obj.attr = 1;
Object.seal(obj);
obj.attr = 1.5;
delete obj.attr; // fail
Object.freeze can make objects completely unmodified:
The code copy is as follows:
var obj = { };
obj.attr = 1;
Object.freeze(obj);
obj.attr = 1.5; // fail
obj.attr2 = 2; //fail
Then you may ask again, how do you know if an object has been preventedExtensions, seal or freeze? The answer is to call Object.isExtensible , Object.isSealed , and Object.isFrozen respectively. The usage of these three functions is relatively simple and no longer cumbersome.
In general, the object can be further strictly controlled through attribute descriptors and the rigor of program logic is strengthened. The only disadvantage is that ES5 is basically implemented in IE9 (IE9 does not support strict mode yet). Considering that the domestic IE8 share is still relatively high, this set of things can only be used in mobile browsers and Node.js.