You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: 1-js/9-object-inheritance/01-property-flags-descriptors/article.md
+72-46Lines changed: 72 additions & 46 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,11 +1,9 @@
1
1
2
-
# Property flags and descriptors [todo move to objects?]
3
-
4
-
Now as we know how to work with primitives and several concrete object-based types, let's return to objects in general.
2
+
# Property flags and descriptors
5
3
6
4
As we know, objects can store properties.
7
5
8
-
But an object property is actually more complex thing than just a "key-value" mapping.
6
+
Till now, a property was a simple "key-value" pair to us. But an object property is actually more complex and tunable thing.
9
7
10
8
[cut]
11
9
@@ -17,22 +15,22 @@ Object properties, besides a **`value`**, have three special attributes (so-call
17
15
-**`enumerable`** -- if `true`, then listed in loops, otherwise not listed.
18
16
-**`configurable`** -- if `true`, the property can be deleted and these attributes can be modified, otherwise not.
19
17
20
-
We didn't see them yet, because by default they are concealed. When we create a property "the usual way", all of them are `true`. But we also can change them any time.
18
+
We didn't see them yet, because generally they do not show up. When we create a property "the usual way", all of them are `true`. But we also can change them any time.
21
19
22
-
First, let's see how to read the flags.
20
+
First, let's see how to get those flags.
23
21
24
-
The method [Object.getOwnPropertyDescriptor](mdn:js/Object/getOwnPropertyDescriptor) allows to query the information about a property.
22
+
The method [Object.getOwnPropertyDescriptor](mdn:js/Object/getOwnPropertyDescriptor) allows to query the *full*information about a property.
25
23
26
24
The syntax is:
27
25
```js
28
26
let descriptor =Object.getOwnPropertyDescriptor(obj, propertyName);
29
27
```
30
28
31
29
`obj`
32
-
: The object to get information about.
30
+
: The object to get information from.
33
31
34
32
`propertyName`
35
-
: The name of the property of interest.
33
+
: The name of the property.
36
34
37
35
The returned value is a so-called "property descriptor" object: it contains the value and all the flags.
38
36
@@ -46,17 +44,17 @@ let user = {
46
44
let descriptor =Object.getOwnPropertyDescriptor(user, 'name');
47
45
48
46
alert( JSON.stringify(descriptor, null, 2 ) );
49
-
/* descriptor:
47
+
/*property descriptor:
50
48
{
51
49
"value": "John",
52
50
"writable": true,
53
51
"enumerable": true,
54
52
"configurable": true
55
53
}
56
-
*/
54
+
*/
57
55
```
58
56
59
-
Now, we'll use [Object.defineProperty](mdn:js/Object/defineProperty) to change flags.
57
+
To change the flags, we can use [Object.defineProperty](mdn:js/Object/defineProperty).
Otherwise, it creates the property with the provided value and flags. Please note, that if a flag is not supplied, it is assumed `false`.
71
+
If the property exist, it updates its flags, otherwise, it creates the property with the given value and flags. Please note, that if a flag is not supplied, it is assumed `false`.
76
72
77
73
For instance, here a property `name` is created with all falsy flags:
78
74
79
75
```js run
80
76
let user = {};
81
77
78
+
*!*
82
79
Object.defineProperty(user, "name", {
83
80
value:"John"
84
81
});
82
+
*/!*
85
83
86
84
let descriptor =Object.getOwnPropertyDescriptor(user, 'name');
87
85
88
86
alert( JSON.stringify(descriptor, null, 2 ) );
89
-
/* compare it with "normally created" user.name above:
Compare it with "normally created" user.name above: now all flags are falsy. If that's not what we want then we'd better to set them to `true` in the `descriptor`.
Normally, a built-in `toString` for objects is non-enumerable, it does not show up in `for..in`. So we'll make ours behave the same.
148
+
Normally, a built-in `toString` for objects is non-enumerable, it does not show up in `for..in`. But if we add `toString` of our own, then by default it shows up in `for..in`.
149
+
150
+
...But if we don't like it, then we can set `enumerable:false`. Then it won't appear in `for..in` loop, just like the built-in one:
```smart header="Errors appear only in use strict"
227
-
In non-strict mode, there are no errors for writing to read-only properties and such, flag-violating actions are silently ignored.
236
+
In the non-strict mode, no errors occur when writing to read-only properties and such. But the operation still won't succeed. Flag-violating actions are just silently ignored in non-strict.
228
237
```
229
238
230
-
## Many properties at once
239
+
## Object.defineProperties
240
+
241
+
There's a method [Object.defineProperties(obj, descriptors)](mdn:js/Object/defineProperties) that allows to define many properties at once.
242
+
243
+
The syntax is:
244
+
245
+
```js
246
+
Object.defineProperties(obj, {
247
+
prop1: descriptor1,
248
+
prop2: descriptor2
249
+
// ...
250
+
});
251
+
```
231
252
232
-
There's a method [Object.defineProperties(obj, descriptors)](mdn:js/Object/defineProperties) that allows to define many properties at once:
253
+
For instance:
233
254
234
255
```js
235
256
Object.defineProperties(user, {
236
-
name: { writable:false },
237
-
surname: { ... },
257
+
name: { value:"John", writable:false },
258
+
surname: { value:"Smith", writable:false },
238
259
// ...
239
260
});
240
261
```
241
262
242
-
And, to get all descriptors, use [Object.getOwnPropertyDescriptors(obj)](mdn:js/Object/getOwnPropertyDescriptors).
263
+
So, we can set many properties at once.
264
+
265
+
## Object.getOwnPropertyDescriptors
243
266
244
-
Together they can be used as an "property flags-aware" way of cloning an object:
267
+
To get many descriptors at once, we can use the method [Object.getOwnPropertyDescriptors(obj)](mdn:js/Object/getOwnPropertyDescriptors).
268
+
269
+
Together with `Object.defineProperties` it can be used as an "flags-aware" way of cloning an object:
245
270
246
271
```js
247
272
let clone =Object.defineProperties({}, Object.getOwnPropertyDescriptors(obj));
248
273
```
249
274
250
-
(For the clone to be fully identical, we need to care about one more thing: "prototype", we'll see into it soon in the chapter [todo])
275
+
Normally when we clone an object, we use an assignment to copy properties, like this:
276
+
277
+
```js
278
+
for(let key in user) {
279
+
clone[key] = user[key]
280
+
}
281
+
```
282
+
283
+
...But that does not copy flags. So if we want a "better" clone then `Object.defineProperties` is preferred.
251
284
252
285
## Sealing an object globally
253
286
254
-
Property descriptors allow to forbid modifications of individual properties.
287
+
Property descriptors work at the level of individual properties.
255
288
256
-
There are also methods that limit access to the whole object:
289
+
There are also methods that limit access to the *whole* object:
0 commit comments