Property Flags and Descriptors
JavaScript Property Flags and Descriptors (JavaScript属性标志和描述符)
Objects are capable of storing properties. Unlike a regular property, an object property is considered a more powerful and flexible thing.
In this chapter, we are going to represent to you several additional options for configuration.
(对象能够存储属性。 与常规属性不同,对象属性被认为是功能更强大、更灵活的东西。
在本章中,我们将向您介绍几个额外的配置选项。)
Property Flags
Property Flags (属性标记)
Object properties include three specific attributes (besides the value). They are called flags. (对象属性包括三个特定属性(值除外)。它们被称为旗帜。)
They can be:
writable - in the case it’s true, the value can be modified. Otherwise, it’s considered read-only. (writable -如果为true ,则可以修改该值。否则,它将被视为只读。)
enumerable -when it’s true, then it’s listed inside the loop. Otherwise- not listed. (enumerable -如果为true ,则会在循环中列出。否则-未列出。)
configurable-in case it’s true, then the property may be deleted, and the attributes may be changed. Otherwise, not. (configurable -如果为true ,则可能会删除属性,并更改属性。否则,不行。)
Now, let’s check out the ways of getting the flags. (现在,让我们来看看获取标记的方法。)
Object.getOwnPropertyDescriptor
The syntax of the Object.getOwnPropertyDescriptor method is the following:
let descriptor = Object.getOwnPropertyDescriptor(obj, propName);
The returned value will be the so-called “property-descriptor” object, which encompasses all the flags. (返回值将是所谓的“property-descriptor”对象,其中包含所有标志。)
Here is an example:
let book = {
name: "Javascript"
};
let descriptor = Object.getOwnPropertyDescriptor(book, 'name');
console.log(JSON.stringify(descriptor, null, 2));
/* property descriptor:
{
"value": "Javascript",
"writable": true,
"enumerable": true,
"configurable": true
}
*/
The Object.defineProperty can be used for changing the flags. Its syntax is demonstrated below:
Object.defineProperty(obj, propName, descriptor);
In case the property exists, the defineProperty will update its flags. In another way, it will generate a property with a particular value and flags, and if a flag is not provided, it will be assumed as false. (如果属性存在, defineProperty将更新其标志。换句话说,它将生成一个具有特定值和标志的属性,如果没有提供标志,它将被假定为false。)
A property name, created with false flags, will look like this:
let book = {};
Object.defineProperty(book, "name", {
value: "Javascript"
});
let descriptor = Object.getOwnPropertyDescriptor(book, 'name');
console.log(JSON.stringify(descriptor, null, 2));
/*
{
"value": "Javascript",
"writable": false,
"enumerable": false,
"configurable": false
}
*/
So, after a comparison with a correctly created book.name, shown in the examples above, all flags are false in this case. If it’s not what you want, it is recommended to set them true in the descriptor. (因此,在与正确创建的book.name (如上面的示例所示)进行比较后,在这种情况下,所有标志都是false。如果这不是您想要的,建议在描述符中将其设置为true。)
Further, we will demonstrate the effects of the flags. (此外,我们将演示旗帜的效果。)
Using Non-Writable Flag
Using Non-Writable Flag (使用不可写标志)
For transforming the book.name into a non-writable one, it’s necessary to change the writable flag like this:
let book = {
name: "Javascript"
};
Object.defineProperty(book, "name", {
writable: false
});
book.name = "HTML"; // Error: Cannot assign to read only property 'name'
console.log(book.name);
After calling the code above, no one will be able to change the name of your user. It will be possible only after using their defineProperty and overriding yours. (调用上述代码后,任何人都无法更改您的用户名。只有在使用他们的defineProperty并覆盖您的之后,才有可能。)
The Usage of Non-enumerable Flag
The Usage of Non-enumerable Flag (不可枚举标志的使用)
In this paragraph, we will show you how to insert a custom toString to the user. Commonly, a built-in toString is considered non-enumerable for objects. And, it doesn’t occur inside for..in. (在本段中,我们将向您展示如何向用户插入自定义toString。 通常,对于对象,内置的toString被认为是不可枚举的。 而且,它不会发生在里面…在里面。)
After adding your own toString, then it will occur in for..in as follows:
let book = {
name: "Javascript",
toString() {
return this.name;
}
};
// By default, our two properties are listed.
for (let key in book) {
console.log(key); // name, toString
}
Also, you can set enumerable:false, then it won’t occur inside a for..in loop. Here is how you can do it:
let book = {
name: "Javascript",
toString() {
return this.name;
}
};
Object.defineProperty(book, "toString", {
enumerable: false
});
// toString disappears:
for (let key in book) {
console.log(key); // name
}
Also, non-enumerable objects are eliminated from Object.keys this way:
let book = {
name: "Javascript",
toString() {
return this.name;
}
};
Object.defineProperty(book, "toString", {
enumerable: false
});
// toString disappears:
console.log(Object.keys(book)); // name
The Usage of Non-Configurable Flag
The Usage of Non-Configurable Flag (不可配置标志的使用)
A non-configurable flag or configurable:false exists for built-in objects and properties, too. Note, that it is not possible to remove a non-configurable property.
Here is an example of Math.PI, which is non-configurable, non-enumerable, and non-writable at the same time:
let descriptor = Object.getOwnPropertyDescriptor(Math, 'PI');
console.log(JSON.stringify(descriptor, null, 2));
/*
{
"value": 3.141592653589793,
"writable": false,
"enumerable": false,
"configurable": false
}
*/
The value of Math.PI can’t be changed or overwritten:
Math.PI = 3; // Error
// delete Math.PI won't work either
Please note that transforming a property into non-configurable is a one-way road: it is impossible to get it back using defineProperty. There is another notable exception, as well: non-configurable doesn’t mean non-writable. Hence, a value of a property that is non-configurable but writable can be modified.
The main purpose of configurable: false is restraining from changes to property flags and its removal and not the changes to its value.
More About Object.defineProperties
More About Object.defineProperties (有关Object.defineProperties的更多信息)
The Object.defineProperties(obj, descriptors) method allows specifying multiple properties simultaneously. (Object.defineProperties (obj, descriptors)方法允许同时指定多个属性。)
The syntax of Object.defineProperties(obj, descriptors) is the following:
Object.defineProperties(obj, {
property1: descriptor1,
property2: descriptor2
// ...
});
To be more precise, let’s consider an example:
Object.defineProperties(book, {
book1: {
value: "Javascript",
writable: false
},
book2: {
value: "Html",
writable: false
},
// ...
});
As you can see, multiple properties are set at once. (如您所见,同时设置了多个属性。)
Observing Object.getOwnPropertyDescriptors
Observing Object.getOwnPropertyDescriptors (观察Object.getOwnPropertyDescriptors)
This method can be used for receiving all the property descriptors at the same time. (此方法可用于同时接收所有属性描述符。)
It can be used as a flag-aware means to clone an object along with Object.defineProperties like this:
let clone = Object.defineProperties({}, Object.getOwnPropertyDescriptors(obj));
As a rule, while cloning an object, an assignment is used for copying properties:
for (let key in book) {
clone[key] = book[key]
}
Note that it can’t clone flags. To have a better result, it is recommended to use Object.defineProperties. (请注意,它无法克隆标志。为了获得更好的结果,建议使用Object.defineProperties。)