diff --git a/1-js/04-object-basics/03-symbol/article.md b/1-js/04-object-basics/03-symbol/article.md index 55599cccb..222cd6ba2 100644 --- a/1-js/04-object-basics/03-symbol/article.md +++ b/1-js/04-object-basics/03-symbol/article.md @@ -1,89 +1,86 @@ -# Symbol type +# O tipo Symbol -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. +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. -Till now we've been using only strings. Now let's see the benefits that symbols can give us. +Até agora, vimos apenas utilizando *strings*. Então, vejamos os benefícios que *symbols* nos dão. -## Symbols +## Símbolos -A "symbol" represents a unique identifier. +Um "símbolo" representa um único identicador. -A value of this type can be created using `Symbol()`: +Um valor deste tipo, pode ser criado utilizando `Symbol()`: ```js -// id is a new symbol +// 'id' é um novo símbolo let id = Symbol(); ``` -We can also give symbol a description (also called a symbol name), mostly useful for debugging purposes: +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): ```js run -// id is a symbol with the description "id" +// 'id' é um símbolo com a descrição "id" let id = Symbol("id"); ``` -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. +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. -For instance, here are two symbols with the same description -- they are not equal: +Por exemplo, aqui estão dois símbolos com a mesma descrição -- eles não são iguais: ```js run let id1 = Symbol("id"); let id2 = Symbol("id"); *!* -alert(id1 == id2); // false +alert(id1 == id2); // false (falso) */!* ``` -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. +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. -````warn header="Symbols don't auto-convert to a string" -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. +````warn header="Símbolos não são auto-convertidos para strings" +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. -For instance, this `alert` will show an error: +Por exemplo, este `alert` exibirá um erro: ```js run let id = Symbol("id"); *!* alert(id); // TypeError: Cannot convert a Symbol value to a string + // TypeError: Não é possível converter um valor 'Symbol' para uma 'string' */!* ``` -That's a "language guard" against messing up, because strings and symbols are fundamentally different and should not occasionally convert one into another. +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. -If we really want to show a symbol, we need to explicitly call `.toString()` on it, like here: +Se realmente quisermos exibir um *symbol*, temos que explicitamente invocar `.toString()` sobre ele, como aqui: ```js run let id = Symbol("id"); *!* -alert(id.toString()); // Symbol(id), now it works +alert(id.toString()); // 'Symbol(id)', agora funciona */!* ``` -Or get `symbol.description` property to show the description only: +Ou empregar a propriedade `symbol.description` para apenas mostrar a sua descrição: ```js run let id = Symbol("id"); *!* -alert(id.description); // id +alert(id.description); // 'id' */!* ``` ```` -## "Hidden" properties +## Propriedades "Ocultas" -Symbols allow us to create "hidden" properties of an object, that no other part of code can occasionally access or overwrite. +Símbolos permitem-nos criar propriedades "ocultas" para um objeto, que nenhuma outra parte do código as possa aceder ou alterar. -<<<<<<< HEAD -For instance, if we want to store an "identifier" for the object `user`, we can use a symbol as a key for it: -======= -For instance, if we're working with `user` objects, that belong to a third-party code. We'd like to add identifiers to them. +Por exemplo, se estivermos a trabalhar com objetos `user`, que pertençam a código de terceiros. E queremos de adicionar identicadores a eles. -Let's use a symbol key for it: ->>>>>>> 852ee189170d9022f67ab6d387aeae76810b5923 +Vamos utilizar uma chave *symbol* para isso: ```js run -let user = { // belongs to another code +let user = { // pertence a outro código name: "John" }; @@ -91,45 +88,45 @@ let id = Symbol("id"); user[id] = 1; -alert( user[id] ); // we can access the data using the symbol as the key +alert( user[id] ); // podemos aceder aos dados usando o 'symbol' como chave (key) ``` -What's the benefit of using `Symbol("id")` over a string `"id"`? +Qual o benefício de se usar `Symbol("id")` sobre uma *string* `"id"`? -Let's make the example a bit deeper to see that. +Façamos um exemplo um pouco mais aprofundado para o vermos. -Imagine that another script wants to have its own "id" property inside `user`, for its own purposes. That may be another JavaScript library, so the scripts are completely unaware of each other. +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. -Then that script can create its own `Symbol("id")`, like this: +Então, aquele programa pode criar o seu próprio `Symbol("id")`, desta forma: ```js // ... let id = Symbol("id"); -user[id] = "Their id value"; +user[id] = "O seu 'id' é válido"; ``` -There will be no conflict, because symbols are always different, even if they have the same name. +Não haverá conflito, porque símbolos são sempre diferentes, mesmo que tenham o mesmo nome. -Now note that if we used a string `"id"` instead of a symbol for the same purpose, then there *would* be a conflict: +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: ```js run let user = { name: "John" }; -// Our script uses "id" property -user.id = "Our id value"; +// O nosso script utiliza uma propriedade "id" +user.id = "O nosso valor 'id'"; -// ...Another script also wants "id" for its purposes... +// ...Um outro script também quer "id" para os seus fins... -user.id = "Their id value" -// Boom! overwritten by another script! +user.id = "O seu valor 'id'" +// Boom! Alterado pelo outro script! ``` -### Symbols in a literal +### Símbolos num literal -If we want to use a symbol in an object literal, we need square brackets. +Se quisermos utilizar um *symbol* num objeto literal, precisamos de parênteses retos. -Like this: +Desta forma: ```js let id = Symbol("id"); @@ -137,17 +134,18 @@ let id = Symbol("id"); let user = { name: "John", *!* - [id]: 123 // not "id: 123" + [id]: 123 // não "id: 123" */!* }; ``` -That's because we need the value from the variable `id` as the key, not the string "id". -### Symbols are skipped by for..in +Isto, porque precisamos do valor que está na variável `id` como chave (*key*), não da *string* "id". -Symbolic properties do not participate in `for..in` loop. +### Símbolos são saltados num *for..in* -For instance: +Propriedades simbólicas não são consideradas num laço (*loop*) `for..in`. + +Por exemplo: ```js run let id = Symbol("id"); @@ -158,16 +156,16 @@ let user = { }; *!* -for (let key in user) alert(key); // name, age (no symbols) +for (let key in user) alert(key); // 'name', 'age' (nenhum símbolo) */!* -// the direct access by the symbol works +// o acesso direto por meio do símbolo funciona alert( "Direct: " + user[id] ); ``` -That's a part of the general "hiding" concept. If another script or a library loops over our object, it won't unexpectedly access a symbolic property. +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. -In contrast, [Object.assign](mdn:js/Object/assign) copies both string and symbol properties: +Em contraste, [Object.assign](mdn:js/Object/assign) copia ambas as propriedades *string* e *symbol*: ```js run let id = Symbol("id"); @@ -180,113 +178,114 @@ let clone = Object.assign({}, user); alert( clone[id] ); // 123 ``` -There's no paradox here. That's by design. The idea is that when we clone an object or merge objects, we usually want *all* properties to be copied (including symbols like `id`). +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`). -````smart header="Property keys of other types are coerced to strings" -We can only use strings or symbols as keys in objects. Other types are converted to strings. +````smart header="Chaves de propriedades de outros tipos são convertidas para strings" +Podemos apenas utilizar *strings* ou *symbols* como chaves em objetos. Outros tipos são forçados para *strings*. -For instance, a number `0` becomes a string `"0"` when used as a property key: +Por exemplo, um número `0` torna-se numa *string* `"0"` quando usado como chave de uma propriedade: ```js run let obj = { - 0: "test" // same as "0": "test" + 0: "test" // o mesmo que "0": "test" }; -// both alerts access the same property (the number 0 is converted to string "0") +// ambos os *alerts* acedem à mesma propriedade (o número 0 é convertido para a *string* "0") alert( obj["0"] ); // test -alert( obj[0] ); // test (same property) +alert( obj[0] ); // test (a mesma propriedade) ``` ```` -## Global symbols +## Símbolos globais -As we've seen, usually all symbols are different, even if they have the same names. But sometimes we want same-named symbols to be same entities. +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. -For instance, different parts of our application want to access symbol `"id"` meaning exactly the same property. +Por exemplo, diferentes partes na nossa aplicação pretendem aceder ao *symbol* `"id"`, significando este uma única mesma propriedade. -To achieve that, there exists a *global symbol registry*. We can create symbols in it and access them later, and it guarantees that repeated accesses by the same name return exactly the same symbol. +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*. -In order to create or read a symbol in the registry, use `Symbol.for(key)`. +Para criar e ler um *symbol* do registo, use `Symbol.for(key)`. -That call checks the global registry, and if there's a symbol described as `key`, then returns it, otherwise creates a new symbol `Symbol(key)` and stores it in the registry by the given `key`. +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`. -For instance: +Por exemplo: ```js run -// read from the global registry -let id = Symbol.for("id"); // if the symbol did not exist, it is created +// lê a partir do registo global +let id = Symbol.for("id"); // se o símbolo não existir, ele o cria -// read it again +// volta a ler let idAgain = Symbol.for("id"); -// the same symbol -alert( id === idAgain ); // true +// é o mesmo símbolo +alert( id === idAgain ); // true (verdadeiro) ``` -Symbols inside the registry are called *global symbols*. If we want an application-wide symbol, accessible everywhere in the code -- that's what they are for. +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. -```smart header="That sounds like Ruby" -In some programming languages, like Ruby, there's a single symbol per name. +```smart header="Isto parece Ruby" +Em algumas linguagens de programação, como Ruby, existe um único *symbol* por nome. -In JavaScript, as we can see, that's right for global symbols. +Em JavaScript, como podemos ver, esses são símbolos globais. ``` ### Symbol.keyFor -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. +Para símbolos globais, não apenas `Symbol.for(key)` retorna um *symbol* por nome, mas existe uma chamada inversa: `Symbol.keyFor(sym)`, que faz ao contrário - retorna um nome de um símbolo global. -For instance: +Por exemplo: ```js run let sym = Symbol.for("name"); let sym2 = Symbol.for("id"); -// get name from symbol -alert( Symbol.keyFor(sym) ); // name -alert( Symbol.keyFor(sym2) ); // id +// Obtenha o nome do 'symbol' +alert( Symbol.keyFor(sym) ); // 'name' +alert( Symbol.keyFor(sym2) ); // 'id' ``` -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 return `undefined`. +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`. -For instance: +Por exemplo: ```js run -alert( Symbol.keyFor(Symbol.for("name")) ); // name, global symbol +alert( Symbol.keyFor(Symbol.for("name")) ); // 'name', símbolo global -alert( Symbol.keyFor(Symbol("name2")) ); // undefined, the argument isn't a global symbol +alert( Symbol.keyFor(Symbol("name2")) ); // undefined, o argumento não é um símbolo global ``` -## System symbols +## Símbolos do sistema -There exist many "system" symbols that JavaScript uses internally, and we can use them to fine-tune various aspects of our objects. +Existem muitos símbolos do "sistema" que o JavaScript usa internamente, e os podemos utilizar para afinar vários aspetos dos nossos objetos. -They are listed in the specification in the [Well-known symbols](https://tc39.github.io/ecma262/#sec-well-known-symbols) table: +Eles vêm listados na especificação, na tabela [Well-known symbols](https://tc39.github.io/ecma262/#sec-well-known-symbols): - `Symbol.hasInstance` - `Symbol.isConcatSpreadable` - `Symbol.iterator` - `Symbol.toPrimitive` -- ...and so on. +- ... e assim por diante. + +Por exemplo, `Symbol.toPrimitive` permite-nos descrever a conversão objeto-para-primitivo. Veremos o seu uso muito em breve. -For instance, `Symbol.toPrimitive` allows us to describe object to primitive conversion. We'll see its use very soon. +Outros *symbols* também se tornarão familiares quando estudarmos as funcionalidades correspondentes na linguagem. -Other symbols will also become familiar when we study the corresponding language features. +## Sumário -## Summary +`Symbol`, é um tipo primitivo para identicadores únicos. -`Symbol` is a primitive type for unique identifiers. +Símbolos são criados pela chamada a `Symbol()`, com uma descrição opcional. -Symbols are created with `Symbol()` call with an optional description. +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. -Symbols are always different values, even if they have the same name. If we want same-named symbols to be equal, then we should use the global registry: `Symbol.for(key)` returns (creates if needed) a global symbol with `key` as the name. Multiple calls of `Symbol.for` return exactly the same symbol. +Símbolos têm dois principais casos práticos: -Symbols have two main use cases: +1. "Ocultação" de propriedades de objetos. -1. "Hidden" object properties. - 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 occasionally listed. Also it won't be accessed directly, because another script does not have our symbol, so it will not occasionally intervene into its actions. + 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 . - So we can "covertly" hide something into objects that we need, but others should not see, using symbolic properties. + Assim, podemos "secretamente" esconder em objetos algo que precisemos, e que outros não possam ver, empregando propriedades simbólicas. -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. +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. -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 methods and syntax constructs adhere to a common agreement that they are. And the one who explicitly calls the aforementioned methods probably understands well what he's doing. +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.