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/04-object-basics/08-symbol/article.md
+12-24Lines changed: 12 additions & 24 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,16 +1,9 @@
1
1
2
2
# Symbol type
3
3
4
-
By specification, only two primitive types may serve as object property keys:
4
+
By specification, object property keys may be either of string type, or of symbol type. Not numbers, not booleans, only strings or symbols, these two types.
5
5
6
-
- string type, or
7
-
- symbol type.
8
-
9
-
Otherwise, if one uses another type, such as number, it's autoconverted to string. So that `obj[1]` is the same as `obj["1"]`, and `obj[true]` is the same as `obj["true"]`.
10
-
11
-
Until now we've been using only strings.
12
-
13
-
Now let's explore symbols, see what they can do for us.
6
+
Till now we've been using only strings. Now let's see the benefits that symbols can give us.
14
7
15
8
## Symbols
16
9
@@ -19,17 +12,18 @@ A "symbol" represents a unique identifier.
19
12
A value of this type can be created using `Symbol()`:
20
13
21
14
```js
15
+
// id is a new symbol
22
16
let id =Symbol();
23
17
```
24
18
25
-
Upon creation, we can give symbols a description (also called a symbol name), mostly useful for debugging purposes:
19
+
Upon creation, we can give symbol a description (also called a symbol name), mostly useful for debugging purposes:
26
20
27
21
```js
28
22
// id is a symbol with the description "id"
29
23
let id =Symbol("id");
30
24
```
31
25
32
-
Symbols are guaranteed to be unique. Even if we create many symbols with exactly the same description, they are different values. The description is just a label that doesn't affect anything.
26
+
Symbols are guaranteed to be unique. Even if we create many symbols with the same description, they are different values. The description is just a label that doesn't affect anything.
33
27
34
28
For instance, here are two symbols with the same description -- they are not equal:
35
29
@@ -44,8 +38,6 @@ alert(id1 == id2); // false
44
38
45
39
If you are familiar with Ruby or another language that also has some sort of "symbols" -- please don't be misguided. JavaScript symbols are different.
46
40
47
-
So, to summarize, a symbol is a "primitive unique value" with an optional description. Let's see where we can use them.
48
-
49
41
````warn header="Symbols don't auto-convert to a string"
50
42
Most values in JavaScript support implicit conversion to a string. For instance, we can `alert` almost any value, and it will work. Symbols are special. They don't auto-convert.
51
43
@@ -61,7 +53,6 @@ alert(id); // TypeError: Cannot convert a Symbol value to a string
61
53
That's a "language guard" against messing up, because strings and symbols are fundamentally different and should not accidentally convert one into another.
62
54
63
55
If we really want to show a symbol, we need to explicitly call `.toString()` on it, like here:
64
-
65
56
```js run
66
57
let id = Symbol("id");
67
58
*!*
@@ -70,7 +61,6 @@ alert(id.toString()); // Symbol(id), now it works
70
61
```
71
62
72
63
Or get `symbol.description` property to show the description only:
73
-
74
64
```js run
75
65
let id = Symbol("id");
76
66
*!*
@@ -82,7 +72,6 @@ alert(id.description); // id
82
72
83
73
## "Hidden" properties
84
74
85
-
86
75
Symbols allow us to create "hidden" properties of an object, that no other part of code can accidentally access or overwrite.
87
76
88
77
For instance, if we're working with `user` objects, that belong to a third-party code. We'd like to add identifiers to them.
@@ -103,9 +92,9 @@ alert( user[id] ); // we can access the data using the symbol as the key
103
92
104
93
What's the benefit of using `Symbol("id")` over a string `"id"`?
105
94
106
-
As `user` objects belong to another codebase, it's unsafe to add fields to them, since we might affect pre-defined behavior in that other codebase. However, symbols cannot be accessed accidentally. The third-party code won't be aware of newly defined symbols, so it's safe to add symbols to the `user` objects.
95
+
As `user` objects belongs to another code, and that code also works with them, we shouldn't just add any fields to it. That's unsafe. But a symbol cannot be accessed accidentally, the third-party code probably won't even see it, so it's probably all right to do.
107
96
108
-
Also, imagine that another script wants to have its own identifier inside `user`, for its own purposes.
97
+
Also, imagine that another script wants to have its own identifier inside `user`, for its own purposes. That may be another JavaScript library, so that the scripts are completely unaware of each other.
109
98
110
99
Then that script can create its own `Symbol("id")`, like this:
111
100
@@ -169,7 +158,7 @@ for (let key in user) alert(key); // name, age (no symbols)
169
158
*/!*
170
159
171
160
// the direct access by the symbol works
172
-
alert( "Direct: "+ user[id] );// Direct: 123
161
+
alert( "Direct: "+ user[id] );
173
162
```
174
163
175
164
[Object.keys(user)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys) also ignores them. That's a part of the general "hiding symbolic properties" principle. If another script or a library loops over our object, it won't unexpectedly access a symbolic property.
@@ -217,12 +206,12 @@ Symbols inside the registry are called *global symbols*. If we want an applicati
217
206
```smart header="That sounds like Ruby"
218
207
In some programming languages, like Ruby, there's a single symbol per name.
219
208
220
-
In JavaScript, as we can see, that's true for global symbols.
209
+
In JavaScript, as we can see, that's right for global symbols.
221
210
```
222
211
223
212
### Symbol.keyFor
224
213
225
-
We have seen that for global symbols, `Symbol.for(key)` returns a symbol by name. To do the opposite -- return a name by global symbol -- we can use: `Symbol.keyFor(sym)`:
214
+
For global symbols, not only `Symbol.for(key)` returns a symbol by name, but there's a reverse call: `Symbol.keyFor(sym)`, that does the reverse: returns a name by a global symbol.
226
215
227
216
For instance:
228
217
@@ -238,7 +227,7 @@ alert( Symbol.keyFor(sym2) ); // id
238
227
239
228
The `Symbol.keyFor` internally uses the global symbol registry to look up the key for the symbol. So it doesn't work for non-global symbols. If the symbol is not global, it won't be able to find it and returns `undefined`.
240
229
241
-
That said, all symbols have the`description` property.
230
+
That said, any symbols have `description` property.
242
231
243
232
For instance:
244
233
@@ -279,11 +268,10 @@ Symbols are always different values, even if they have the same name. If we want
279
268
Symbols have two main use cases:
280
269
281
270
1. "Hidden" object properties.
282
-
283
271
If we want to add a property into an object that "belongs" to another script or a library, we can create a symbol and use it as a property key. A symbolic property does not appear in `for..in`, so it won't be accidentally processed together with other properties. Also it won't be accessed directly, because another script does not have our symbol. So the property will be protected from accidental use or overwrite.
284
272
285
273
So we can "covertly" hide something into objects that we need, but others should not see, using symbolic properties.
286
274
287
275
2. There are many system symbols used by JavaScript which are accessible as `Symbol.*`. We can use them to alter some built-in behaviors. For instance, later in the tutorial we'll use `Symbol.iterator` for [iterables](info:iterable), `Symbol.toPrimitive` to setup [object-to-primitive conversion](info:object-toprimitive) and so on.
288
276
289
-
Technically, symbols are not 100% hidden. There is a built-in method [Object.getOwnPropertySymbols(obj)](mdn:js/Object/getOwnPropertySymbols) that allows us to get all symbols. Also there is a method named [Reflect.ownKeys(obj)](mdn:js/Reflect/ownKeys) that returns *all* keys of an object including symbolic ones. But most libraries, built-in functions and syntax constructs don't use these methods.
277
+
Technically, symbols are not 100% hidden. There is a built-in method [Object.getOwnPropertySymbols(obj)](mdn:js/Object/getOwnPropertySymbols) that allows us to get all symbols. Also there is a method named [Reflect.ownKeys(obj)](mdn:js/Reflect/ownKeys) that returns *all* keys of an object including symbolic ones. So they are not really hidden. But most libraries, built-in functions and syntax constructs don't use these methods.
0 commit comments