This is the 27th day of my participation in the August More Text Challenge

The preface

We know that objects can store properties. But most of the time, attributes are just a simple “key-value” pair for us. But object properties are actually more flexible and powerful things, and today we’ll look at the configuration options for properties.

Attribute flags

Object attributes, in addition to value, have three special properties, which are called attribute flags:

  1. Writable – If true, the value can be modified, otherwise it is only readable.
  2. Enumerable – If it is true, it is listed in the loop, otherwise it is not.
  3. This feature can be deleted and modified without any additional information, if the configured information is true, exercising any additional control system.

We don’t usually see them. When we create a property, they all default to true. And we can change them at any time.

How do I get attribute flags

To inquire about the attribute Object. GetOwnPropertyDescriptor method allows complete information.

let descriptor = Object.getOwnPropertyDescriptor(obj, propertyName);
Copy the code

Obj The object from which to obtain information. PropertyName Indicates the name of the property. The return value is a so-called “attribute descriptor” object: it contains the value and all the flags. Example:

let user = { name: "coolFish" }; let descriptor = Object.getOwnPropertyDescriptor(user, 'name'); alert( JSON.stringify(descriptor, null, 2 ) ); /* Property descripers: {"value": "coolFish", "writable": true, "enumerable": true, "64x ": true} */Copy the code

To modify the tag, we can use Object.defineProperty.

Object.defineProperty(obj, propertyName, descriptor)
Copy the code

Obj, propertyName Object and properties to which the descriptor is applied. Descriptor Property descriptor object to be applied. If the attribute exists, defineProperty updates its flag. Otherwise, it creates an attribute with the given value and flag; In this case, if no flag is provided, it is assumed to be false.

In this example, we create a property whose properties default to false

let user = {};
​
Object.defineProperty(user, "name", {
  value: "coolFish"
});
​
let descriptor = Object.getOwnPropertyDescriptor(user, 'name');
​
alert( JSON.stringify(descriptor, null, 2 ) );
/*
{
  "value": "coolFish",
  "writable": false,
  "enumerable": false,
  "configurable": false
}
 */
Copy the code

Compare this to the “commonly created” user.name above: all flags are now false. If that’s not what we want, then we better set them to true in descriptor.

Setting read-only Properties

We can set user.name to read-only by changing the writable flag (user.name cannot be reassigned)

let user = {
  name: "coolFish"
};
​
Object.defineProperty(user, "name", {
  writable: false
});
​
user.name = "Pete"; // Error: Cannot assign to read only property 'name'
Copy the code

Now no one can change our user’s name unless they apply their defineProperty to override our user’s name.

Non-enumerable property

We add a custom toString to user. Object’s built-in toString is not enumerable, and it does not show up in for… In the. But if we add our own toString, then by default it will be displayed in for… In the

let user = { name: "coolFish", toString() { return this.name; }}; // By default, both of our attributes are listed: for (let key in user) alert(key); // name, toStringCopy the code

If we don’t like it, we can set Enumerable: False. Then it won’t appear in for… The in loop, like the built-in toString, simply means that these property descriptors allow us to emulate many native properties and make our business more flexible to meet expectations

let user = { name: "coolFish", toString() { return this.name; }}; Object.defineProperty(user, "toString", { enumerable: false }); // Now our toString is gone: for (let key in user) alert(key); // nameCopy the code

Non-enumerable properties are also excluded by object.keys

alert(Object.keys(user)); // name
Copy the code

In this way, we can control the scope of some methods or variables, and be more flexible