Skip to content

Commit e8d5265

Browse files
committed
Update Symbol article.
1 parent 6275846 commit e8d5265

File tree

1 file changed

+54
-64
lines changed

1 file changed

+54
-64
lines changed

1-js/04-object-basics/08-symbol/article.md

Lines changed: 54 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@
33

44
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.
55

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.
77

88
## Símbolos
99

10-
Um "símbolo" representa um único identicador.
10+
Um "símbolo" representa um único identificador.
1111

1212
Um valor deste tipo, pode ser criado utilizando `Symbol()`:
1313

@@ -16,14 +16,14 @@ Um valor deste tipo, pode ser criado utilizando `Symbol()`:
1616
let id = Symbol();
1717
```
1818

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):
2020

2121
```js run
2222
// 'id' é um símbolo com a descrição "id"
2323
let id = Symbol("id");
2424
```
2525

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.
2727

2828
Por exemplo, aqui estão dois símbolos com a mesma descrição -- eles não são iguais:
2929

@@ -36,32 +36,34 @@ alert(id1 == id2); // false (falso)
3636
*/!*
3737
```
3838

39-
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.
4040

4141
````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.
4343
44-
Por exemplo, este `alert` exibirá um erro:
44+
Por exemplo, este `alert` irá mostrar um erro:
4545
4646
```js run
4747
let id = Symbol("id");
4848
*!*
4949
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')
5151
*/!*
5252
```
5353
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:
5557
56-
Se realmente quisermos exibir um *symbol*, temos que explicitamente invocar `.toString()` sobre ele, como aqui:
5758
```js run
5859
let id = Symbol("id");
5960
*!*
6061
alert(id.toString()); // 'Symbol(id)', agora funciona
6162
*/!*
6263
```
6364
64-
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+
6567
```js run
6668
let id = Symbol("id");
6769
*!*
@@ -73,9 +75,9 @@ alert(id.description); // 'id'
7375

7476
## Propriedades "Ocultas"
7577

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.
7779

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.
7981

8082
Vamos utilizar uma chave *symbol* para isso:
8183

@@ -93,22 +95,22 @@ alert( user[id] ); // podemos aceder aos dados usando o 'symbol' como chave (key
9395

9496
Qual o benefício de se usar `Symbol("id")` sobre uma *string* `"id"`?
9597

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.
9799

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.
99101

100102
Então, aquele programa pode criar o seu próprio `Symbol("id")`, desta forma:
101103

102104
```js
103105
// ...
104106
let id = Symbol("id");
105107

106-
user[id] = "O seu 'id' é válido";
108+
user[id] = "O valor 'id' do outro programa";
107109
```
108110

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.
110112

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:
112114

113115
```js run
114116
let user = { name: "John" };
@@ -118,13 +120,13 @@ user.id = "O nosso valor 'id'";
118120

119121
// ...Um outro script também quer "id" para os seus fins...
120122

121-
user.id = "O seu valor 'id'"
123+
user.id = "O valor 'id' dos outros"
122124
// Boom! Alterado pelo outro script!
123125
```
124126

125-
### Símbolos num literal
127+
### Símbolos num objeto literal
126128

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.
128130

129131
Desta forma:
130132

@@ -134,12 +136,12 @@ let id = Symbol("id");
134136
let user = {
135137
name: "John",
136138
*!*
137-
[id]: 123 // não "id: 123"
139+
[id]: 123 // não "id": 123
138140
*/!*
139141
};
140142
```
141143

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".
143145

144146
### Símbolos são saltados num *for..in*
145147

@@ -163,7 +165,7 @@ for (let key in user) alert(key); // 'name', 'age' (nenhum símbolo)
163165
alert( "Direct: " + user[id] );
164166
```
165167

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.
167169

168170
Em contraste, [Object.assign](mdn:js/Object/assign) copia ambas as propriedades *string* e *symbol*:
169171

@@ -178,55 +180,37 @@ let clone = Object.assign({}, user);
178180
alert( clone[id] ); // 123
179181
```
180182

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`).
198184

199185
## Símbolos globais
200186

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.
204188

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*.
206190

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)`.
208192

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`.
210194

211195
Por exemplo:
212196

213197
```js run
214198
// 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
216200

217-
// volta a ler
201+
// volta a ler (talvez a partir de outra secção no código)
218202
let idAgain = Symbol.for("id");
219203

220204
// é o mesmo símbolo
221205
alert( id === idAgain ); // true (verdadeiro)
222206
```
223207

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.
225209

226210
```smart header="Isto parece Ruby"
227211
Em algumas linguagens de programação, como Ruby, existe um único *symbol* por nome.
228212
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.
230214
```
231215

232216
### Symbol.keyFor
@@ -236,27 +220,34 @@ Para símbolos globais, não apenas `Symbol.for(key)` retorna um *symbol* por no
236220
Por exemplo:
237221

238222
```js run
223+
// obtenha o símbolo a partir do nome
239224
let sym = Symbol.for("name");
240225
let sym2 = Symbol.for("id");
241226

242-
// Obtenha o nome do 'symbol'
227+
// obtenha o nome a partir do 'symbol'
243228
alert( Symbol.keyFor(sym) ); // 'name'
244229
alert( Symbol.keyFor(sym2) ); // 'id'
245230
```
246231

247232
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`.
248233

234+
Deste modo, todos os símbolos têm uma propriedade `description`.
235+
249236
Por exemplo:
250237

251238
```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
253244

254-
alert( Symbol.keyFor(Symbol("name2")) ); // undefined, o argumento não é um símbolo global
245+
alert( localSymbol.description ); // 'name'
255246
```
256247

257248
## Símbolos do sistema
258249

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.
260251

261252
Eles vêm listados na especificação, na tabela [Well-known symbols](https://tc39.github.io/ecma262/#sec-well-known-symbols):
262253

@@ -266,26 +257,25 @@ Eles vêm listados na especificação, na tabela [Well-known symbols](https://tc
266257
- `Symbol.toPrimitive`
267258
- ... e assim por diante.
268259

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.
270261

271262
Outros *symbols* também se tornarão familiares quando estudarmos as funcionalidades correspondentes na linguagem.
272263

273-
## Sumário
264+
## Resumo
274265

275-
`Symbol`, é um tipo primitivo para identicadores únicos.
266+
`Symbol`, é um tipo primitivo para identificadores únicos.
276267

277268
Símbolos são criados pela chamada a `Symbol()`, com uma descrição opcional.
278269

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.
280271

281272
Símbolos têm dois principais casos práticos:
282273

283274
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.
284276

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.
288278

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.
290280

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. Mas muitas 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

Comments
 (0)