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
+54-64Lines changed: 54 additions & 64 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -3,11 +3,11 @@
3
3
4
4
Segundo a especificação, as chaves das propriedades dos objetos podem ser quer do tipo *string* como do tipo *symbol*. Não números, não booleanos, apenas *strings* (cadeias-de-carateres) ou *symbols* (símbolos), estes dois tipos.
5
5
6
-
Até agora, vimos apenas utilizando *strings*. Então, vejamos os benefícios que *symbols* nos dão.
6
+
Até agora, vimos apenas utilizando *strings*. Então, vejamos os benefícios que *symbols* nos podem dar.
7
7
8
8
## Símbolos
9
9
10
-
Um "símbolo" representa um único identicador.
10
+
Um "símbolo" representa um único identificador.
11
11
12
12
Um valor deste tipo, pode ser criado utilizando `Symbol()`:
13
13
@@ -16,14 +16,14 @@ Um valor deste tipo, pode ser criado utilizando `Symbol()`:
16
16
let id =Symbol();
17
17
```
18
18
19
-
Podemos também dar ao símbolo uma descrição (igualmente chamada de nome do símbolo), sendo mais útil para fins de *debugging* (depuração de erros):
19
+
Quando o criamos, podemos dar ao símbolo uma descrição (também chamada de nome do símbolo), que é mais útil para fins de *debugging* (depuração de erros):
20
20
21
21
```js run
22
22
// 'id' é um símbolo com a descrição "id"
23
23
let id =Symbol("id");
24
24
```
25
25
26
-
Símbolos têm a garantia de serem únicos. Mesmo que criemos muitos símbolos com a mesma descrição, eles são valores diferentes. A descrição apenas é um rótulo, sem efeito algum.
26
+
Símbolos têm a garantia de serem únicos. Mesmo que criemos muitos símbolos com a mesma descrição, eles são valores diferentes. A descrição é apenas um rótulo, não afeta nada.
27
27
28
28
Por exemplo, aqui estão dois símbolos com a mesma descrição -- eles não são iguais:
Se tiver familiaridade com Ruby ou outra linguagem que também empregue algum tipo de "símbolos" -- por favor, não se confunda. Símbolos em JavaScript são diferentes.
39
+
Se você tiver familiaridade com Ruby, ou outra linguagem que também tenha algum tipo de "símbolos" -- por favor, não se confunda. Em JavaScript, os símbolos são diferentes.
40
40
41
41
````warn header="Símbolos não são auto-convertidos para strings"
42
-
Muitos valores em JavaScript suportam conversão implícita para *string*. Por exemplo, podemos usar `alert` com quase qualquer valor, e funcionará. Símbolos são especiais. Não há auto-conversão.
42
+
A maior parte dos valores em JavaScript suporta conversão implícita para *string*. Por exemplo, podemos usar `alert` com quase qualquer valor, e irá funcionar. Símbolos são especiais. Eles não são automaticamente convertidos.
43
43
44
-
Por exemplo, este `alert` exibirá um erro:
44
+
Por exemplo, este `alert` irá mostrar um erro:
45
45
46
46
```js run
47
47
let id = Symbol("id");
48
48
*!*
49
49
alert(id); // TypeError: Cannot convert a Symbol value to a string
50
-
// TypeError: Não é possível converter um valor 'Symbol' para uma 'string'
50
+
// (TypeError: Não é possível converter um valor 'Symbol' para uma 'string')
51
51
*/!*
52
52
```
53
53
54
-
Existe uma "salvaguarda na linguagem" contra a mistura de ambos, porque *strings* e *symbols* são fundamentalmente diferentes, e não deveriam ser convertidos de um tipo para o outro ao acaso.
54
+
Existe uma "salvaguarda na linguagem" contra a confusão, porque *strings* e *symbols* são fundamentalmente diferentes, e não deveriam ser acidentalmente convertidos de um destes tipos para o outro.
55
+
56
+
Se realmente quisermos mostrar um *symbol*, teremos que explicitamente invocar `.toString()` sobre ele, como aqui:
55
57
56
-
Se realmente quisermos exibir um *symbol*, temos que explicitamente invocar `.toString()` sobre ele, como aqui:
Ou empregar a propriedade `symbol.description` para apenas mostrar a sua descrição:
65
+
Ou usar a propriedade `symbol.description` para mostrar apenas a sua descrição:
66
+
65
67
```js run
66
68
let id = Symbol("id");
67
69
*!*
@@ -73,9 +75,9 @@ alert(id.description); // 'id'
73
75
74
76
## Propriedades "Ocultas"
75
77
76
-
Símbolos permitem-nos criar propriedades "ocultas" para um objeto, que nenhuma outra parte do código as possa aceder ou alterar.
78
+
Símbolos nos permitem criar propriedades "ocultas" num objeto, que nenhuma outra parte do código possa acidentalmente aceder ou alterar.
77
79
78
-
Por exemplo, se estivermos a trabalhar com objetos `user`, que pertençam a código de terceiros. E queremos de adicionar identicadores a eles.
80
+
Por exemplo, se estivermos a trabalhar com um objeto `user`, que pertence a um código de terceiros, e quisermos adicionar identificadores a ele.
79
81
80
82
Vamos utilizar uma chave *symbol* para isso:
81
83
@@ -93,22 +95,22 @@ alert( user[id] ); // podemos aceder aos dados usando o 'symbol' como chave (key
93
95
94
96
Qual o benefício de se usar `Symbol("id")` sobre uma *string*`"id"`?
95
97
96
-
Façamos um exemplo um pouco mais aprofundado para o vermos.
98
+
Como o objeto `user` pertence a outro código, e aquele código trabalha bem com ele, não deveríamos sómente adicionar quaisquer propriedades a ele. Isso não é seguro. Mas, um símbolo não pode ser acedido acidentalmente, o código de terceiros provavelmente nem o irá ver, então talvez seja a coisa certa a fazer.
97
99
98
-
Imagine que um outro programa (*script*) quer a sua própria propriedade "id" dentro de `user`, para seus próprios fins. Isto pode estar noutra biblioteca (*library*) de JavaScript, por isso os *scripts* podem não ter nenhum conhecimento um do outro.
100
+
De igual modo, imagine que ainda um outro programa (*script*) quer ter o seu próprio identificador dentro de `user`, para seus próprios fins. Isto pode estar noutra biblioteca (*library*) de JavaScript, por isso os *scripts* podem não ter nenhum conhecimento um do outro.
99
101
100
102
Então, aquele programa pode criar o seu próprio `Symbol("id")`, desta forma:
101
103
102
104
```js
103
105
// ...
104
106
let id =Symbol("id");
105
107
106
-
user[id] ="O seu 'id' é válido";
108
+
user[id] ="O valor 'id' do outro programa";
107
109
```
108
110
109
-
Não haverá conflito, porque símbolos são sempre diferentes, mesmo que tenham o mesmo nome.
111
+
Não haverá conflito entre o nosso identificador e o dos outros, porque símbolos são sempre diferentes, mesmo que tenham o mesmo nome.
110
112
111
-
Agora, note que se tivéssemos empregue uma *string*`"id"` em vez de um *symbol* para o mesmo propósito, então *haveria* um conflito:
113
+
...Mas, se tivéssemos usado uma *string*`"id"` em vez de um *symbol* para o mesmo propósito, então *haveria* um conflito:
112
114
113
115
```js run
114
116
let user = { name:"John" };
@@ -118,13 +120,13 @@ user.id = "O nosso valor 'id'";
118
120
119
121
// ...Um outro script também quer "id" para os seus fins...
120
122
121
-
user.id="O seu valor 'id'"
123
+
user.id="O valor 'id' dos outros"
122
124
// Boom! Alterado pelo outro script!
123
125
```
124
126
125
-
### Símbolos num literal
127
+
### Símbolos num objeto literal
126
128
127
-
Se quisermos utilizar um *symbol* num objeto literal, precisamos de parênteses retos.
129
+
Se quisermos utilizar um *symbol* num objeto literal`{...}`, precisamos de parênteses retos.
128
130
129
131
Desta forma:
130
132
@@ -134,12 +136,12 @@ let id = Symbol("id");
134
136
let user = {
135
137
name:"John",
136
138
*!*
137
-
[id]:123// não "id: 123"
139
+
[id]:123// não "id": 123
138
140
*/!*
139
141
};
140
142
```
141
143
142
-
Isto, porque precisamos do valor que está na variável `id` como chave (*key*), não da *string* "id".
144
+
Isto, porque precisamos do valor que está na variável `id` como chave, não da *string* "id".
143
145
144
146
### Símbolos são saltados num *for..in*
145
147
@@ -163,7 +165,7 @@ for (let key in user) alert(key); // 'name', 'age' (nenhum símbolo)
163
165
alert( "Direct: "+ user[id] );
164
166
```
165
167
166
-
Isto, é uma parte do conceito geral de "ocultação". Se, um outro programa (*script*) ou uma biblioteca (*library*) percorrer o nosso objeto com um ciclo (*loop*), não irá inadvertidamente aceder a uma propriedade simbólica.
168
+
`Object.keys(user)` também os ignora. Isto, é uma parte do conceito geral de "ocultação de propriedades simbólicas". Se, um outro programa ou uma biblioteca percorrer o nosso objeto com um ciclo (*loop*), não irá inadvertidamente aceder a uma propriedade simbólica.
167
169
168
170
Em contraste, [Object.assign](mdn:js/Object/assign) copia ambas as propriedades *string* e *symbol*:
169
171
@@ -178,55 +180,37 @@ let clone = Object.assign({}, user);
178
180
alert( clone[id] ); // 123
179
181
```
180
182
181
-
Não existe nenhum paradoxo aqui. Esse é o propósito. A ideia é que ao clonar ou fundir objetos, queremos geralmente *todas* as propriedades copiadas (incluindo símbolos como `id`).
182
-
183
-
````smart header="Chaves de propriedades de outros tipos são convertidas para strings"
184
-
Podemos apenas utilizar *strings* ou *symbols* como chaves em objetos. Outros tipos são forçados para *strings*.
185
-
186
-
Por exemplo, um número `0` torna-se numa *string* `"0"` quando usado como chave de uma propriedade:
187
-
188
-
```js run
189
-
let obj = {
190
-
0: "test" // o mesmo que "0": "test"
191
-
};
192
-
193
-
// ambos os *alerts* acedem à mesma propriedade (o número 0 é convertido para a *string* "0")
194
-
alert( obj["0"] ); // test
195
-
alert( obj[0] ); // test (a mesma propriedade)
196
-
```
197
-
````
183
+
Não existe nenhum paradoxo aqui. Essa é a implementação. A ideia é que ao clonar ou fundir (*merge*) objetos, queremos geralmente *todas* as propriedades copiadas (incluindo símbolos como `id`).
198
184
199
185
## Símbolos globais
200
186
201
-
Como vimos, geralmente todos os *symbols* são diferentes, mesmo que tenham o mesmo nome. Mas, por vezes queremos que *symbols* com o mesmo nome se refiram às mesmas entidades.
202
-
203
-
Por exemplo, diferentes partes na nossa aplicação pretendem aceder ao *symbol*`"id"`, significando este uma única mesma propriedade.
187
+
Como vimos, geralmente todos os *symbols* são diferentes, mesmo que tenham o mesmo nome. Mas, por vezes queremos que *symbols* com o mesmo nome se refiram às mesmas entidades. Por exemplo, diferentes partes na nossa aplicação pretendem aceder ao *symbol*`"id"`, sendo este exatamente a mesma propriedade.
204
188
205
-
Para alcançar isso, existe um *registo global de símbolos* (*global symbol registry*). Podemos criar *symbols* nele e acedê-los mais tarde, e ele garante que acessos repetidos ao mesmo nome retornem exatamente o mesmo *symbol*.
189
+
Para alcançar isso, existe um *registo global de símbolos* (*global symbol registry*). Podemos criar *symbols* nele e os aceder mais tarde, e ele garante que acessos repetidos ao mesmo nome retornem exatamente o mesmo *symbol*.
206
190
207
-
Para criar e ler um *symbol* do registo, use `Symbol.for(key)`.
191
+
Para ler (e criar, se ausente) um *symbol* do registo, use `Symbol.for(key)`.
208
192
209
-
Essa chamada verifica o registo global (*global registry*), e se houver um *symbol* descrito como `key`, ele o retorna, senão cria um novo *symbol* com `Symbol(key)` e o armazena no registo sob a chave `key`.
193
+
Essa chamada verifica o registo global, e se houver um *symbol* descrito como `key`, ele o retorna, senão cria um novo *symbol* com `Symbol(key)` e o armazena no registo sob a chave `key`.
210
194
211
195
Por exemplo:
212
196
213
197
```js run
214
198
// lê a partir do registo global
215
-
let id =Symbol.for("id"); // se o símbolo não existir, ele o cria
199
+
let id =Symbol.for("id"); // se o símbolo não existir, ele é criado
216
200
217
-
// volta a ler
201
+
// volta a ler (talvez a partir de outra secção no código)
218
202
let idAgain =Symbol.for("id");
219
203
220
204
// é o mesmo símbolo
221
205
alert( id === idAgain ); // true (verdadeiro)
222
206
```
223
207
224
-
Símbolos dentro do registo são chamados de *símbolos globais* (*global symbols*). Quando quisermos um *symbol* para toda a aplicação, acessível em qualquer parte do código -- é para o que eles servem.
208
+
Símbolos dentro do registo são chamados de *símbolos globais* (*global symbols*). Quando queremos um *symbol* para toda a aplicação, acessível em qualquer parte do código -- é para isso que eles servem.
225
209
226
210
```smart header="Isto parece Ruby"
227
211
Em algumas linguagens de programação, como Ruby, existe um único *symbol* por nome.
228
212
229
-
Em JavaScript, como podemos ver, esses são símbolos globais.
213
+
Em JavaScript, como podemos ver, esses são os símbolos globais.
230
214
```
231
215
232
216
### Symbol.keyFor
@@ -236,27 +220,34 @@ Para símbolos globais, não apenas `Symbol.for(key)` retorna um *symbol* por no
236
220
Por exemplo:
237
221
238
222
```js run
223
+
// obtenha o símbolo a partir do nome
239
224
let sym =Symbol.for("name");
240
225
let sym2 =Symbol.for("id");
241
226
242
-
//Obtenha o nome do 'symbol'
227
+
//obtenha o nome a partir do 'symbol'
243
228
alert( Symbol.keyFor(sym) ); // 'name'
244
229
alert( Symbol.keyFor(sym2) ); // 'id'
245
230
```
246
231
247
232
O `Symbol.keyFor` utiliza internamente o registo global de símbolos para procurar pela chave do símbolo. Por isso, não funciona para símbolos não globais. Se o símbolo não for global, não será capaz de o encontrar e retorna `undefined`.
248
233
234
+
Deste modo, todos os símbolos têm uma propriedade `description`.
235
+
249
236
Por exemplo:
250
237
251
238
```js run
252
-
alert( Symbol.keyFor(Symbol.for("name")) ); // 'name', símbolo global
239
+
let globalSymbol =Symbol.for("name");
240
+
let localSymbol =Symbol("name");
241
+
242
+
alert( Symbol.keyFor(globalSymbol) ); // 'name', símbolo global
243
+
alert( Symbol.keyFor(localSymbol) ); // 'undefined', não global
253
244
254
-
alert( Symbol.keyFor(Symbol("name2")) ); //undefined, o argumento não é um símbolo global
245
+
alert( localSymbol.description ); //'name'
255
246
```
256
247
257
248
## Símbolos do sistema
258
249
259
-
Existem muitos símbolos do "sistema" que o JavaScript usa internamente, e os podemos utilizar para afinar vários aspetos dos nossos objetos.
250
+
Existem muitos símbolos do "sistema" que o JavaScript usa internamente, e nós os podemos utilizar para afinar vários aspetos dos nossos objetos.
260
251
261
252
Eles vêm listados na especificação, na tabela [Well-known symbols](https://tc39.github.io/ecma262/#sec-well-known-symbols):
262
253
@@ -266,26 +257,25 @@ Eles vêm listados na especificação, na tabela [Well-known symbols](https://tc
266
257
-`Symbol.toPrimitive`
267
258
- ... e assim por diante.
268
259
269
-
Por exemplo, `Symbol.toPrimitive`permite-nos descrever a conversão objeto-para-primitivo. Veremos o seu uso muito em breve.
260
+
Por exemplo, `Symbol.toPrimitive` nos permite descrever a conversão objeto-para-primitivo. Veremos o seu uso muito em breve.
270
261
271
262
Outros *symbols* também se tornarão familiares quando estudarmos as funcionalidades correspondentes na linguagem.
272
263
273
-
## Sumário
264
+
## Resumo
274
265
275
-
`Symbol`, é um tipo primitivo para identicadores únicos.
266
+
`Symbol`, é um tipo primitivo para identificadores únicos.
276
267
277
268
Símbolos são criados pela chamada a `Symbol()`, com uma descrição opcional.
278
269
279
-
Símbolos são sempre valores diferentes, mesmo que tenham o mesmo nome. Se quisermos que símbolos com o mesmo nome sejam iguais, teremos de utilizar o registo global: `Symbol.for(key)` retorna (cria, se necessário) um símbolo global com `key` como nome. Múltiplas chamadas a `Symbol.for` retornam exatamente o mesmo símbolo.
270
+
Símbolos são sempre valores diferentes, mesmo que tenham o mesmo nome. Se quisermos que símbolos com o mesmo nome sejam iguais, teremos de utilizar o registo global: `Symbol.for(key)` retorna (cria, se necessário) um símbolo global com `key` como nome. Múltiplas chamadas a `Symbol.for`com a mesma `key`retornam exatamente o mesmo símbolo.
280
271
281
272
Símbolos têm dois principais casos práticos:
282
273
283
274
1. "Ocultação" de propriedades de objetos.
275
+
Se quisermos adicionar uma propriedade a um objeto, "pertencendo" este a outro programa ou biblioteca, podemos criar um símbolo e o usar como a chave dessa propriedade. Uma propriedade simbólica não aparece num `for..in`, por isso não será acidentalmente processada juntamente com outras propriedades. Também, não será acedida diretamente, porque um outro programa não terá o nosso símbolo. Assim, a propriedade estará protegida contra uso acidental ou alteração.
284
276
285
-
Se quisermos adicionar uma propriedade a um objeto que "peetença" a outro programa ou biblioteca, podemos criar um símbolo e o utilizar como a chave da propriedade. Uma propriedade simbólica não aparece num `for..in`, por isso em certas ocasiões não será listada. Também, não será diretamente acedida porque outro programa não terá o nosso símbolo, e portanto não irá inadvertidamente intervir nas suas ações .
286
-
287
-
Assim, podemos "secretamente" esconder em objetos algo que precisemos, e que outros não possam ver, empregando propriedades simbólicas.
277
+
Assim, podemos "secretamente" esconder nos objetos algo que precisemos, que outros não devam ver, empregando propriedades simbólicas.
288
278
289
-
2. Existem muitos símbolos de sistema usados por JavaScript que podem ser acedidos com `Symbol.*`. Podemos os utilizar para alterar alguns comportamentos padrão (*built-in*). Por exemplo, mais adiante no tutorial usaremos`Symbol.iterator` para [iterables](info:iterable) (iteráveis), `Symbol.toPrimitive` para configurar a [object-to-primitive conversion](info:object-toprimitive) (conversão objeto-para-primitivo), e assim por diante.
279
+
2. Existem muitos símbolos de sistema usados por JavaScript que podem ser acedidos com `Symbol.*`. Podemos os utilizar para alterar alguns comportamentos pré-definidos (*built-in*). Por exemplo, mais adiante no tutorial iremos usar`Symbol.iterator` para [iterables](info:iterable) (iteráveis), `Symbol.toPrimitive` para configurar a [object-to-primitive conversion](info:object-toprimitive) (conversão objeto-para-primitivo), e assim por diante.
290
280
291
-
Tecnicamente, símbolos não são 100% ocultados. Existe um método incorporado (*built-in*) [Object.getOwnPropertySymbols(obj)](mdn:js/Object/getOwnPropertySymbols) que nos permite obter todos os símbolos. Também, existe um método chamado [Reflect.ownKeys(obj)](mdn:js/Reflect/ownKeys) que retorna *todas* as chaves de um objeto, incluindo as simbólicas. Assim, eles não estão realmente ocultos. Masmuitas bibliotecas, métodos e construções sintáticas incorporados aderem ao comum acordo de que estão. E, quem invocar os métodos agora mencionados provavelmente compreende bem o que está a fazer.
281
+
Tecnicamente, símbolos não são 100% ocultados. Existe um método incorporado (*built-in*) [Object.getOwnPropertySymbols(obj)](mdn:js/Object/getOwnPropertySymbols) que nos permite obter todos os símbolos. Também, existe um método chamado [Reflect.ownKeys(obj)](mdn:js/Reflect/ownKeys) que retorna *todas* as chaves de um objeto, incluindo as simbólicas. Assim, eles não estão realmente ocultos. Mas, tanto muitas bibliotecas, como métodos e construções sintáticas incorporados não usam esses métodos.
0 commit comments