From f3fb7d2927a16e702ac7683957ff2981c86d31c5 Mon Sep 17 00:00:00 2001 From: odsantos Date: Tue, 22 Oct 2019 05:42:38 +0100 Subject: [PATCH 1/8] translate '01-object' directory files --- .../01-object/2-hello-object/solution.md | 2 - .../01-object/2-hello-object/task.md | 14 +- .../01-object/3-is-empty/_js.view/solution.js | 2 +- .../01-object/3-is-empty/_js.view/test.js | 4 +- .../01-object/3-is-empty/solution.md | 2 +- .../01-object/3-is-empty/task.md | 13 +- .../01-object/4-const-object/solution.md | 10 +- .../01-object/4-const-object/task.md | 6 +- .../01-object/5-sum-object/task.md | 8 +- .../8-multiply-numeric/_js.view/source.js | 6 +- .../8-multiply-numeric/_js.view/test.js | 8 +- .../01-object/8-multiply-numeric/task.md | 20 +- 1-js/04-object-basics/01-object/article.md | 473 +++++++++--------- 1-js/04-object-basics/index.md | 2 +- 14 files changed, 281 insertions(+), 289 deletions(-) diff --git a/1-js/04-object-basics/01-object/2-hello-object/solution.md b/1-js/04-object-basics/01-object/2-hello-object/solution.md index 60083b963..dff006076 100644 --- a/1-js/04-object-basics/01-object/2-hello-object/solution.md +++ b/1-js/04-object-basics/01-object/2-hello-object/solution.md @@ -1,5 +1,4 @@ - ```js let user = {}; user.name = "John"; @@ -7,4 +6,3 @@ user.surname = "Smith"; user.name = "Pete"; delete user.name; ``` - diff --git a/1-js/04-object-basics/01-object/2-hello-object/task.md b/1-js/04-object-basics/01-object/2-hello-object/task.md index 2841a058f..c0e296444 100644 --- a/1-js/04-object-basics/01-object/2-hello-object/task.md +++ b/1-js/04-object-basics/01-object/2-hello-object/task.md @@ -2,13 +2,13 @@ importance: 5 --- -# Hello, object +# Olá, objeto -Write the code, one line for each action: +Escreva o código, uma ação por linha: -1. Create an empty object `user`. -2. Add the property `name` with the value `John`. -3. Add the property `surname` with the value `Smith`. -4. Change the value of the `name` to `Pete`. -5. Remove the property `name` from the object. +1. Crie um objeto vazio (*empty object*) `user`. +2. Adicione a propriedade `name` com o valor `John`. +3. Adicione a propriedade `surname` com o valor `Smith`. +4. Altere o valor de `name` para `Pete`. +5. Remova a propriedade `name` do objeto. diff --git a/1-js/04-object-basics/01-object/3-is-empty/_js.view/solution.js b/1-js/04-object-basics/01-object/3-is-empty/_js.view/solution.js index db3283e49..ca7dc324e 100644 --- a/1-js/04-object-basics/01-object/3-is-empty/_js.view/solution.js +++ b/1-js/04-object-basics/01-object/3-is-empty/_js.view/solution.js @@ -1,6 +1,6 @@ function isEmpty(obj) { for (let key in obj) { - // if the loop has started, there is a property + // se o laço começou, existe uma propriedade return false; } return true; diff --git a/1-js/04-object-basics/01-object/3-is-empty/_js.view/test.js b/1-js/04-object-basics/01-object/3-is-empty/_js.view/test.js index 4db5efabe..400577698 100644 --- a/1-js/04-object-basics/01-object/3-is-empty/_js.view/test.js +++ b/1-js/04-object-basics/01-object/3-is-empty/_js.view/test.js @@ -1,9 +1,9 @@ describe("isEmpty", function() { - it("returns true for an empty object", function() { + it("retorna verdadeiro para um objeto vazio", function() { assert.isTrue(isEmpty({})); }); - it("returns false if a property exists", function() { + it("retorna falso se uma propriedade existir", function() { assert.isFalse(isEmpty({ anything: false })); diff --git a/1-js/04-object-basics/01-object/3-is-empty/solution.md b/1-js/04-object-basics/01-object/3-is-empty/solution.md index b876973b5..6c328fc39 100644 --- a/1-js/04-object-basics/01-object/3-is-empty/solution.md +++ b/1-js/04-object-basics/01-object/3-is-empty/solution.md @@ -1 +1 @@ -Just loop over the object and `return false` immediately if there's at least one property. +Simplemente, percorra (*loop over*) o objeto e imediatamente `return false` se pelo menos houver uma propriedade. diff --git a/1-js/04-object-basics/01-object/3-is-empty/task.md b/1-js/04-object-basics/01-object/3-is-empty/task.md index c438d36a2..a499e6eb7 100644 --- a/1-js/04-object-basics/01-object/3-is-empty/task.md +++ b/1-js/04-object-basics/01-object/3-is-empty/task.md @@ -2,19 +2,18 @@ importance: 5 --- -# Check for emptiness +# Verifique por vazio (*emptiness*) -Write the function `isEmpty(obj)` which returns `true` if the object has no properties, `false` otherwise. - -Should work like that: +Escreva a função `isEmpty(obj)`, que retorna `true` se o objeto não tiver propriedades, e `false` caso contrário. +Deve assim funcionar: ```js let schedule = {}; -alert( isEmpty(schedule) ); // true +alert( isEmpty(schedule) ); // verdadeiro -schedule["8:30"] = "get up"; +schedule["8:30"] = "levante-se"; -alert( isEmpty(schedule) ); // false +alert( isEmpty(schedule) ); // falso ``` diff --git a/1-js/04-object-basics/01-object/4-const-object/solution.md b/1-js/04-object-basics/01-object/4-const-object/solution.md index f73c2f92b..9cb150373 100644 --- a/1-js/04-object-basics/01-object/4-const-object/solution.md +++ b/1-js/04-object-basics/01-object/4-const-object/solution.md @@ -1,8 +1,8 @@ -Sure, it works, no problem. +Com certeza, funciona, sem problemas. -The `const` only protects the variable itself from changing. +A `const` apenas protege a própria variável contra alterações. -In other words, `user` stores a reference to the object. And it can't be changed. But the content of the object can. +Por outras palavras, `user` armazena uma referência ao objeto. E não pode ser alterada. Mas, o conteúdo do objeto pode. ```js run const user = { @@ -10,10 +10,10 @@ const user = { }; *!* -// works +// funciona user.name = "Pete"; */!* -// error +// erro user = 123; ``` diff --git a/1-js/04-object-basics/01-object/4-const-object/task.md b/1-js/04-object-basics/01-object/4-const-object/task.md index a9aada631..a0a1709dc 100644 --- a/1-js/04-object-basics/01-object/4-const-object/task.md +++ b/1-js/04-object-basics/01-object/4-const-object/task.md @@ -2,9 +2,9 @@ importance: 5 --- -# Constant objects? +# Objetos constantes? -Is it possible to change an object declared with `const`? What do you think? +É possível alterar um objeto declarado com `const`? O que acha? ```js const user = { @@ -12,7 +12,7 @@ const user = { }; *!* -// does it work? +// isto funciona? user.name = "Pete"; */!* ``` diff --git a/1-js/04-object-basics/01-object/5-sum-object/task.md b/1-js/04-object-basics/01-object/5-sum-object/task.md index 7e3e048d0..b0caee202 100644 --- a/1-js/04-object-basics/01-object/5-sum-object/task.md +++ b/1-js/04-object-basics/01-object/5-sum-object/task.md @@ -2,9 +2,9 @@ importance: 5 --- -# Sum object properties +# Soma das propriedades de um objeto -We have an object storing salaries of our team: +Temos um objeto armazenando salários da nossa equipa: ```js let salaries = { @@ -14,6 +14,6 @@ let salaries = { } ``` -Write the code to sum all salaries and store in the variable `sum`. Should be `390` in the example above. +Escreva o código para somar todos os salários e armazenar na variável `sum`. Para o exemplo acima, deverá ser `390`. -If `salaries` is empty, then the result must be `0`. \ No newline at end of file +Se `salaries` for vazio, então o resultado deve ser `0`. \ No newline at end of file diff --git a/1-js/04-object-basics/01-object/8-multiply-numeric/_js.view/source.js b/1-js/04-object-basics/01-object/8-multiply-numeric/_js.view/source.js index a02b1e1cb..f2ffe4901 100644 --- a/1-js/04-object-basics/01-object/8-multiply-numeric/_js.view/source.js +++ b/1-js/04-object-basics/01-object/8-multiply-numeric/_js.view/source.js @@ -1,17 +1,17 @@ let menu = { width: 200, height: 300, - title: "My menu" + title: "O meu menu" }; function multiplyNumeric(obj) { - /* your code */ + /* o seu código */ } multiplyNumeric(menu); -alert( "menu width=" + menu.width + " height=" + menu.height + " title=" + menu.title ); +alert( "largura do menu=" + menu.width + " altura=" + menu.height + " título=" + menu.title ); diff --git a/1-js/04-object-basics/01-object/8-multiply-numeric/_js.view/test.js b/1-js/04-object-basics/01-object/8-multiply-numeric/_js.view/test.js index 064e5414f..2ba28f769 100644 --- a/1-js/04-object-basics/01-object/8-multiply-numeric/_js.view/test.js +++ b/1-js/04-object-basics/01-object/8-multiply-numeric/_js.view/test.js @@ -1,17 +1,17 @@ describe("multiplyNumeric", function() { - it("multiplies all numeric properties by 2", function() { + it("multiplica todas as propriedades numéricas por 2", function() { let menu = { width: 200, height: 300, - title: "My menu" + title: "O meu menu" }; let result = multiplyNumeric(menu); assert.equal(menu.width, 400); assert.equal(menu.height, 600); - assert.equal(menu.title, "My menu"); + assert.equal(menu.title, "O meu menu"); }); - it("returns nothing", function() { + it("não retorna nada", function() { assert.isUndefined( multiplyNumeric({}) ); }); diff --git a/1-js/04-object-basics/01-object/8-multiply-numeric/task.md b/1-js/04-object-basics/01-object/8-multiply-numeric/task.md index 33eb89220..54fa7fceb 100644 --- a/1-js/04-object-basics/01-object/8-multiply-numeric/task.md +++ b/1-js/04-object-basics/01-object/8-multiply-numeric/task.md @@ -2,32 +2,30 @@ importance: 3 --- -# Multiply numeric properties by 2 +# Multiplica as propriedades numéricas por 2 -Create a function `multiplyNumeric(obj)` that multiplies all numeric properties of `obj` by `2`. +Crie uma função `multiplyNumeric(obj)` que multiplica todas as proriedades numéricas de `obj` por `2`. -For instance: +Por exemplo: ```js -// before the call +// antes da chamada let menu = { width: 200, height: 300, - title: "My menu" + title: "O meu menu" }; multiplyNumeric(menu); -// after the call +// depois da chamada menu = { width: 400, height: 600, - title: "My menu" + title: "O meu menu" }; ``` -Please note that `multiplyNumeric` does not need to return anything. It should modify the object in-place. - -P.S. Use `typeof` to check for a number here. - +Por favor, note que `multiplyNumeric` não precisa de retornar nada. Deve modificar o próprio objecto. +P.S. Use `typeof` para verificar por um número aqui. diff --git a/1-js/04-object-basics/01-object/article.md b/1-js/04-object-basics/01-object/article.md index 00706750c..baba98e3a 100644 --- a/1-js/04-object-basics/01-object/article.md +++ b/1-js/04-object-basics/01-object/article.md @@ -1,60 +1,60 @@ -# Objects +# Objetos -As we know from the chapter , there are seven data types in JavaScript. Six of them are called "primitive", because their values contain only a single thing (be it a string or a number or whatever). +Como sabemos, pelo capítulo , existem sete tipos de dados em JavaScript. Seis deles são chamados de "primitivos", porque os seus valores apenas contêm uma única coisa (seja ela uma cadeia-de-carateres [*string*], um número, ou o que for). -In contrast, objects are used to store keyed collections of various data and more complex entities. In JavaScript, objects penetrate almost every aspect of the language. So we must understand them first before going in-depth anywhere else. +Em contraste, objetos são empregues para armazenar por meio de uma chave, coleções de vários dados e entidades mais complexas. Em JavaScript, objetos penetram em quase todos os aspetos da linguagem. Portanto, devemos primeiro compreendê-los antes de nos envolvermos detalhadamente em algo mais. -An object can be created with figure brackets `{…}` with an optional list of *properties*. A property is a "key: value" pair, where `key` is a string (also called a "property name"), and `value` can be anything. +Um objeto pode ser criado por chavetas `{…}`, com uma lista opcional de *propriedades*. Uma propriedade é um par "key: value" (chave: valor), onde `key` é uma *string* (também chamada de "nome da propriedade"), e `value` pode ser qualquer coisa. -We can imagine an object as a cabinet with signed files. Every piece of data is stored in its file by the key. It's easy to find a file by its name or add/remove a file. +Podemos imaginar um objeto como um fichário com ficheiros assinados. Cada peça de informação, é armazenada no seu ficheiro ligada a uma chave. É fácil encontrar um ficheiro através do seu nome, ou adicionar/remover um ficheiro. ![](object.svg) -An empty object ("empty cabinet") can be created using one of two syntaxes: +Um objeto vazio ("fichário vazio"), pode ser criado por uma de duas sintaxes: ```js -let user = new Object(); // "object constructor" syntax -let user = {}; // "object literal" syntax +let user = new Object(); // sintaxe de "construtor de objetos" +let user = {}; // sintaxe de "objeto literal" ``` ![](object-user-empty.svg) -Usually, the figure brackets `{...}` are used. That declaration is called an *object literal*. +Geralmente, são utilizadas as chavetas `{...}`. Essa declaração é chamada de *objeto literal*. -## Literals and properties +## Literais e propriedades -We can immediately put some properties into `{...}` as "key: value" pairs: +Podemos imediatamente colocar algumas propriedades dentro das `{...}` como pares "chave: valor" (*key: value*): ```js -let user = { // an object - name: "John", // by key "name" store value "John" - age: 30 // by key "age" store value 30 +let user = { // um objeto + name: "John", // na chave "name" armazene o valor "John" + age: 30 // na chave "age" armazene o valor 30 }; ``` -A property has a key (also known as "name" or "identifier") before the colon `":"` and a value to the right of it. +Uma propriedade, tem uma chave (*key* - também conhecida por "nome" ou "identificador") antes dos dois-pontos `":"` e um valor à sua direita. -In the `user` object, there are two properties: +No objeto `user`, existem duas propriedades: -1. The first property has the name `"name"` and the value `"John"`. -2. The second one has the name `"age"` and the value `30`. +1. A primeira, tem o nome `"name"` e o valor `"John"`. +2. A segunda, tem o nome `"age"` e o valor `30`. -The resulting `user` object can be imagined as a cabinet with two signed files labeled "name" and "age". +O objeto `user` resultante, pode ser imaginado como um fichário com dois ficheiros assinados com as etiquetas "*name*" e "*age*". ![user object](object-user.svg) -We can add, remove and read files from it any time. +Podemos adicionar, remover e ler ficheiros dele a qualquer altura. -Property values are accessible using the dot notation: +Valores de propriedades podem ser acedidos usando a notação por ponto (*dot notation*): ```js -// get fields of the object: +// obtenha os campos do objeto: alert( user.name ); // John alert( user.age ); // 30 ``` -The value can be of any type. Let's add a boolean one: +O valor pode ser de qualquer tipo. Vamos adicionar um booleano: ```js user.isAdmin = true; @@ -62,7 +62,7 @@ user.isAdmin = true; ![user object 2](object-user-isadmin.svg) -To remove a property, we can use `delete` operator: +Para remover uma propriedade, podemos usar o operador `delete`: ```js delete user.age; @@ -70,69 +70,70 @@ delete user.age; ![user object 3](object-user-delete.svg) -We can also use multiword property names, but then they must be quoted: +Podemos também usar nomes de propriedades com múltiplas palavras, mas aí eles têm de estar entre aspas: ```js let user = { name: "John", age: 30, - "likes birds": true // multiword property name must be quoted + "likes birds": true // "likes birds" ("gosta de pássaros") - o nome de propriedade com múltiplas palavras tem de estar entre aspas }; ``` ![](object-user-props.svg) +A última propriedade da lista pode terminar com uma vírgula: -The last property in the list may end with a comma: ```js let user = { name: "John", age: 30*!*,*/!* } ``` -That is called a "trailing" or "hanging" comma. Makes it easier to add/remove/move around properties, because all lines become alike. -## Square brackets +Esta é chamada de vírgula à direita (*trailing comma*) ou "vírgula pendurada" (*hanging comma*). Ela facilita o adicionar/remover/mover propriedades, porque todas as linhas serão semelhantes (as propriedades são separadas por vírgulas). -For multiword properties, the dot access doesn't work: +## Parênteses retos + +Para propriedades com múltiplas palavras, o acesso por ponto não funciona: ```js run -// this would give a syntax error +// isto daria um erro de sintaxe user.likes birds = true ``` -That's because the dot requires the key to be a valid variable identifier. That is: no spaces and other limitations. +Isto, porque o ponto requere que a chave (*key*) seja um identificador de variável válido. Isto é: sem espaços e outras restrições. -There's an alternative "square bracket notation" that works with any string: +Existe uma alternativa, a "notação por parênteses retos", que funciona com qualquer *string* (cadeia-de-carateres): ```js run let user = {}; -// set +// cria user["likes birds"] = true; -// get -alert(user["likes birds"]); // true +// lê +alert(user["likes birds"]); // true ('verdadeiro') -// delete +// remove delete user["likes birds"]; ``` -Now everything is fine. Please note that the string inside the brackets is properly quoted (any type of quotes will do). +Agora, tudo está bem. Por favor, verifique se a *string* dentro dos parênteses retos está própriamente encerrada entre aspas (qualquer tipo de aspas serve). -Square brackets also provide a way to obtain the property name as the result of any expression -- as opposed to a literal string -- like from a variable as follows: +Os parênteses retos, também fornecem uma forma de se obter o nome de uma propriedade como resultado de uma expressão -- em vez de uma *string* literal -- como a partir de uma variável, a exemplo: ```js let key = "likes birds"; -// same as user["likes birds"] = true; +// o mesmo que 'user["likes birds"] = true;' user[key] = true; ``` -Here, the variable `key` may be calculated at run-time or depend on the user input. And then we use it to access the property. That gives us a great deal of flexibility. The dot notation cannot be used in a similar way. +Aqui, a variável `key` pode ser calculada em tempo de execução (*run-time*) ou depender de uma entrada pelo utilizador (*user input*). E depois a utilizamos para aceder à propriedade. Isso, dá-nos um grande grau de flexibilidade. -For instance: +Por exemplo: ```js run let user = { @@ -140,15 +141,13 @@ let user = { age: 30 }; -let key = prompt("What do you want to know about the user?", "name"); +let key = prompt("O que quer saber acerca do utilizador?", "name"); -// access by variable -alert( user[key] ); // John (if enter "name") +// aceda à variável +alert( user[key] ); // John (se a entrada tiver sido "name") ``` -<<<<<<< HEAD -======= -The dot notation cannot be used in a similar way: +A notação por ponto não pode ser usada de forma semelhante: ```js run let user = { @@ -159,42 +158,41 @@ let user = { let key = "name"; alert( user.key ) // undefined ``` ->>>>>>> 852ee189170d9022f67ab6d387aeae76810b5923 -### Computed properties +### Propriedades computadas -We can use square brackets in an object literal. That's called *computed properties*. +Podemos utilizar os parênteses retos num object literal. Chamam-se de *propriedades computadas*. -For instance: +Por exemplo: ```js run -let fruit = prompt("Which fruit to buy?", "apple"); +let fruit = prompt("Que fruta comprar?", "apple"); let bag = { *!* - [fruit]: 5, // the name of the property is taken from the variable fruit + [fruit]: 5, // o nome da propriedade é obtido por meio da variável 'fruit' */!* }; alert( bag.apple ); // 5 if fruit="apple" ``` -The meaning of a computed property is simple: `[fruit]` means that the property name should be taken from `fruit`. +O significado de uma propriedade computada é simples: `[fruit]` diz que o nome da propriedade é obtido por meio de `fruit`. -So, if a visitor enters `"apple"`, `bag` will become `{apple: 5}`. +Assim, se um visitante inserir `"apple"`, `bag` se tornará em `{apple: 5}`. -Essentially, that works the same as: +Essencialmente, isso é o mesmo que: ```js run -let fruit = prompt("Which fruit to buy?", "apple"); +let fruit = prompt("Que fruta comprar?", "apple"); let bag = {}; -// take property name from the fruit variable +// obtenha o nome da propriedade por meio da variável fruit bag[fruit] = 5; ``` -...But looks nicer. +...Mas, tem uma melhor apresentação. -We can use more complex expressions inside square brackets: +Podemos usar expressões mais complexas dentro dos parênteses retos: ```js let fruit = 'apple'; @@ -203,16 +201,14 @@ let bag = { }; ``` -Square brackets are much more powerful than the dot notation. They allow any property names and variables. But they are also more cumbersome to write. - -So most of the time, when property names are known and simple, the dot is used. And if we need something more complex, then we switch to square brackets. - +Parênteses retos, são mais poderosos que a notação por ponto. Eles permitem quaisquer nomes de propriedades e variáveis. Mas, eles também envolvem mais trabalho para escrever. +Assim, a maior parte as vezes, quando nomes de propriedades são conhecidos e simples, o ponto é utilizado. E, se precisarmos de algo mais complexo, mudamos para os parênteses retos. ````smart header="Reserved words are allowed as property names" -A variable cannot have a name equal to one of language-reserved words like "for", "let", "return" etc. +Uma variável, não pode ter um nome igual a uma das palavras reservadas ('keywords') da linguagem, como "for", "let", "return" etc. -But for an object property, there's no such restriction. Any name is fine: +Mas, para uma propriedade de um objeto, não existe tal restrição. Qualquer nome é aceitável: ```js run let obj = { @@ -224,28 +220,27 @@ let obj = { alert( obj.for + obj.let + obj.return ); // 6 ``` -Basically, any name is allowed, but there's a special one: `"__proto__"` that gets special treatment for historical reasons. For instance, we can't set it to a non-object value: +Basicamente, qualquer nome é permitido, mas existe um especial: `"__proto__"`, que tem um tratamento particular por razões históricas. Por exemplo, a ele não podemos atribuir um valor não-objeto: ```js run let obj = {}; obj.__proto__ = 5; -alert(obj.__proto__); // [object Object], didn't work as intended +alert(obj.__proto__); // [object Object], não resultou como esperado ``` -As we see from the code, the assignment to a primitive `5` is ignored. +Como vemos pelo código, a atribuição do primitivo `5` é ignorada. -That can become a source of bugs and even vulnerabilities if we intend to store arbitrary key-value pairs in an object, and allow a visitor to specify the keys. +Isso, pode se tornar numa fonte de erros ('bugs') e até de vulnerabilidades, se pretendermos armazenar pares chave-valor arbitrários num objeto, e permitir a um visitante especificar as chaves ('keys'). -In that case the visitor may choose "__proto__" as the key, and the assignment logic will be ruined (as shown above). +Nesse caso, o the visitante pode escolher "__proto__" como chave, e a lógica de atribuição estará arruinada (como se mostra acima). -There is a way to make objects treat `__proto__` as a regular property, which we'll cover later, but first we need to know more about objects. -There's also another data structure [Map](info:map-set-weakmap-weakset), that we'll learn in the chapter , which supports arbitrary keys. +Existe uma forma de fazer os objetos tratarem `__proto__` como uma propriedade regular, que analisaremos mais adiante, mas primeiro precisamos de saber mais sobre objetos. +Existe também outra estrutura de dados [Map](info:map-set-weakmap-weakset), que aprenderemos no capítulo , que suporta chaves arbitrárias. ```` +## Abreviação do valor da propriedade -## Property value shorthand - -In real code we often use existing variables as values for property names. +Em código real, frequentemente empregamos variáveis semelhantes a valores como nomes de propriedades. For instance: @@ -254,7 +249,7 @@ function makeUser(name, age) { return { name: name, age: age - // ...other properties + // ...outras propriedades }; } @@ -262,103 +257,102 @@ let user = makeUser("John", 30); alert(user.name); // John ``` -In the example above, properties have the same names as variables. The use-case of making a property from a variable is so common, that there's a special *property value shorthand* to make it shorter. +No exemplo acima, propriedades têm os mesmos nomes que as variáveis. O caso prático (*use-case*) de construir uma propriedade com base numa variável é tão comum, que existe uma especial *abreviação do valor da propriedade* (*property value shorthand*) para a tornar mais curta. -Instead of `name:name` we can just write `name`, like this: +Em vez de `name:name`, podemos simplesmente escrever `name`, como abaixo: ```js function makeUser(name, age) { *!* return { - name, // same as name: name - age // same as age: age + name, // o mesmo que name: name + age // o mesmo que age: age // ... }; */!* } ``` -We can use both normal properties and shorthands in the same object: +Podemos empregar ambas, as propriedades normais e as abreviações (*shorthands*) no mesmo objeto: ```js let user = { - name, // same as name:name + name, // o mesmo que name:name age: 30 }; ``` -## Existence check +## Verificação de existência -A notable objects feature is that it's possible to access any property. There will be no error if the property doesn't exist! Accessing a non-existing property just returns `undefined`. It provides a very common way to test whether the property exists -- to get it and compare vs undefined: +Uma particularidade notável de objetos, é que é possível aceder a qualquer propriedade. Não haverá erro se a propriedade não existir! Aceder a uma propriedade não-existente apenas retorna `undefined`. Ela, fornece uma forma muito comum de testar se a propriedade existe -- aceda, e compare o resultado com *undefined*: ```js run let user = {}; -alert( user.noSuchProperty === undefined ); // true means "no such property" +alert( user.noSuchProperty === undefined ); // true, significa "propriedade não existente" (no such property) ``` -There also exists a special operator `"in"` to check for the existence of a property. +Também existe um operador especial, `"in"`, para verificar a existência de uma propriedade. + +A sintaxe é: -The syntax is: ```js "key" in object ``` -For instance: +Por exemplo: ```js run let user = { name: "John", age: 30 }; -alert( "age" in user ); // true, user.age exists -alert( "blabla" in user ); // false, user.blabla doesn't exist +alert( "age" in user ); // true (verdadeiro), 'user.age' existe +alert( "blabla" in user ); // false (falso), 'user.blabla' não existe ``` -Please note that on the left side of `in` there must be a *property name*. That's usually a quoted string. +Por favor, note que no lado esquerdo de `in` deve existir um *nome de propriedade*. Geralmente, é uma *string* entre aspas. -If we omit quotes, that would mean a variable containing the actual name will be tested. For instance: +Se omitirmos as aspas, isso terá o significado de uma variável contendo o atual nome a ser testado. Por exemplo: ```js run let user = { age: 30 }; let key = "age"; -alert( *!*key*/!* in user ); // true, takes the name from key and checks for such property +alert( *!*key*/!* in user ); // true (verdadeiro), recebe o nome por meio de 'key' e procura por tal propriedade ``` -````smart header="Using \"in\" for properties that store `undefined`" -Usually, the strict comparison `"=== undefined"` check works fine. But there's a special case when it fails, but `"in"` works correctly. +````smart header="Using "in" for properties that store "undefined"" +Geralmente, a comparação exata ('strict') para a verificação `"=== undefined"` funciona bem. Mas, existe um caso especial em que falha. Contudo, `"in"` funciona corretamente. -It's when an object property exists, but stores `undefined`: +É quando uma propriedade de um objeto existe, mas possui `undefined` nela armazenado: ```js run let obj = { test: undefined }; -alert( obj.test ); // it's undefined, so - no such property? +alert( obj.test ); // exibe 'undefined', então - tal propriedade não existe? -alert( "test" in obj ); // true, the property does exist! +alert( "test" in obj ); // true (verdadeiro), a propriedade na realidade existe! ``` +No código acima, a propriedade `obj.test` tecnicamente existe. Deste modo, o operador `in` funciona corretamente. -In the code above, the property `obj.test` technically exists. So the `in` operator works right. - -Situations like this happen very rarely, because `undefined` is usually not assigned. We mostly use `null` for "unknown" or "empty" values. So the `in` operator is an exotic guest in the code. +Situações como esta muito raramente ocorrem, porque `undefined` não é usualmente atribuido. Em geral, empregamos `null` para valores "desconhecidos" ou "vazios". Deste modo, o operador `in` é um convidado exótico na codificação. ```` +## O laço "for..in" -## The "for..in" loop +Para navegar por todas as chaves (*keys*) de um objeto, existe uma forma especial de laço (*loop*): `for..in`. Esta, é uma construção completamente diferente da do `for(;;)`, que estudámos antes. -To walk over all keys of an object, there exists a special form of the loop: `for..in`. This is a completely different thing from the `for(;;)` construct that we studied before. - -The syntax: +A sintaxe: ```js for (key in object) { - // executes the body for each key among object properties + // executa o corpo do laço, por cada chave (key) de entre as propriedades do objeto } ``` -For instance, let's output all properties of `user`: +Por exemplo, vamos imprimir todas propriedades de `user`: ```js run let user = { @@ -368,33 +362,32 @@ let user = { }; for (let key in user) { - // keys - alert( key ); // name, age, isAdmin - // values for the keys + // key (chave) + alert( key ); // 'name', 'age', isAdmin' + // valor por chave (key) alert( user[key] ); // John, 30, true } ``` -Note that all "for" constructs allow us to declare the looping variable inside the loop, like `let key` here. - -Also, we could use another variable name here instead of `key`. For instance, `"for (let prop in obj)"` is also widely used. +Note, que todas as construções "for" permitem-nos declarar a variável do laço dentro do ciclo (*loop*), como `let key` aqui. +De igual modo, poderíamos usar aqui um nome de variável differente de `key`. Por exemplo, `"for (let prop in obj)"` também é largamente utilizado. -### Ordered like an object +### Ordenado como um objeto -Are objects ordered? In other words, if we loop over an object, do we get all properties in the same order they were added? Can we rely on this? +Os objetos são ordenados? Por outras palavras, se percorrermos um objeto com um laço, será que obtemos todas as propriedades pela mesma ordem em que foram adicionadas? Poderemos confiar nisso? -The short answer is: "ordered in a special fashion": integer properties are sorted, others appear in creation order. The details follow. +A curta resposta é: "ordenados de um modo especial" - propriedades inteiras são ordenadas de forma crescente, outras aparecem na ordem em que foram criadas. Detalhes a seguir. -As an example, let's consider an object with the phone codes: +Como exemplo, considermos um objeto com indicativos telefónicos de países: ```js run let codes = { - "49": "Germany", - "41": "Switzerland", - "44": "Great Britain", + "49": "Alemanha", + "41": "Suíça", + "44": "Grã Bretanha", // .., - "1": "USA" + "1": "EUA" }; *!* @@ -404,56 +397,59 @@ for (let code in codes) { */!* ``` -The object may be used to suggest a list of options to the user. If we're making a site mainly for German audience then we probably want `49` to be the first. +O objeto, pode ser empregue como sugestão de uma lista de opções para o utilizador. Se, estivermos a construir um *site* maioritariamente para uma audiência Alemã, então provavelmente queremos `49` como o primeiro. -But if we run the code, we see a totally different picture: +Mas, ao correr o código, vemos uma imagem totalmente diferente: -- USA (1) goes first -- then Switzerland (41) and so on. +- EUA (1) vem em primeiro lugar, +- depois a Suiça (41), e assim por adiante. -The phone codes go in the ascending sorted order, because they are integers. So we see `1, 41, 44, 49`. +Os indicativos telefónicos, são ordenados por ordem ascendente, porque são inteiros. Por isso, vemos `1, 41, 44, 49`. ````smart header="Integer properties? What's that?" -The "integer property" term here means a string that can be converted to-and-from an integer without a change. +O termo "propriedade inteira" aqui, significa que uma *string* pode ser convertida para inteiro ('integer') e, de volta reconvertida sem qualquer alteração. -So, "49" is an integer property name, because when it's transformed to an integer number and back, it's still the same. But "+49" and "1.2" are not: +Assim, "49" é um nome de propriedade inteiro porque, ao ser transformado num número inteiro e de volta reconvertido, continua o mesmo. Mas, "+49" e "1.2" não são: ```js run -// Math.trunc is a built-in function that removes the decimal part -alert( String(Math.trunc(Number("49"))) ); // "49", same, integer property -alert( String(Math.trunc(Number("+49"))) ); // "49", not same "+49" ⇒ not integer property -alert( String(Math.trunc(Number("1.2"))) ); // "1", not same "1.2" ⇒ not integer property +// Math.trunc é uma função incorporada (*built-in function*) que remove a parte decimal + +alert( String(Math.trunc(Number("49"))) ); // "49", inalterado ⇒ propriedade inteira + +alert( String(Math.trunc(Number("+49"))) ); // "49", não o mesmo que "+49" ⇒ não é uma propriedade inteira + +alert( String(Math.trunc(Number("1.2"))) ); // "1", não o mesmo que "1.2" ⇒ não é uma propriedade inteira ``` ```` -...On the other hand, if the keys are non-integer, then they are listed in the creation order, for instance: +...Por outro lado, se as chaves (*keys*) forem não-inteiras, elas são listadas segundo a ordem em que foram criadas, por exemplo: ```js run let user = { name: "John", surname: "Smith" }; -user.age = 25; // add one more +user.age = 25; // adicione mais uma propriedade *!* -// non-integer properties are listed in the creation order +// propriedades não-inteiras são listadas segundo a ordem em que foram criadas */!* for (let prop in user) { - alert( prop ); // name, surname, age + alert( prop ); // 'name', 'surname', 'age' } ``` -So, to fix the issue with the phone codes, we can "cheat" by making the codes non-integer. Adding a plus `"+"` sign before each code is enough. +Portanto, para corrigir o problema dos indicativos telefónicos, podemos "aldrabar" tornando-os não-inteiros. Adicionar um sinal de mais `"+"`, antes de cada código é o suficiente. -Like this: +Desta forma: ```js run let codes = { - "+49": "Germany", - "+41": "Switzerland", - "+44": "Great Britain", + "+49": "Alemanha", + "+41": "Suiça", + "+44": "Grã Bretanha", // .., - "+1": "USA" + "+1": "EUA" }; for (let code in codes) { @@ -461,30 +457,30 @@ for (let code in codes) { } ``` -Now it works as intended. +Agora, funciona como pretendido. -## Copying by reference +## Cópia por referência -One of the fundamental differences of objects vs primitives is that they are stored and copied "by reference". +Uma das principais diferenças entre objetos vs primitivos, está em que os primeiros são armazenados e copiados "por referência" (*by reference*). -Primitive values: strings, numbers, booleans -- are assigned/copied "as a whole value". +Valores primitivos: *strings*, números, booleanos -- são atribuidos/copiados como "o próprio valor". -For instance: +Por exemplo: ```js let message = "Hello!"; let phrase = message; ``` -As a result we have two independent variables, each one is storing the string `"Hello!"`. +Como resultado, temos duas variáveis independentes, mas cada uma armazenando a *string* (cadeia-de-carateres) `"Hello!"`. ![](variable-copy-value.svg) -Objects are not like that. +Objetos não são assim. -**A variable stores not the object itself, but its "address in memory", in other words "a reference" to it.** +**Uma variável não armazena o próprio objeto, mas o seu "endereço em memória" (*address in memory*), por outras palavras "uma referência" (*reference*) a ele.** -Here's the picture for the object: +Aqui, está a imagem para o objeto: ```js let user = { @@ -494,25 +490,25 @@ let user = { ![](variable-contains-reference.svg) -Here, the object is stored somewhere in memory. And the variable `user` has a "reference" to it. +Aqui, o objeto é armazenado algures na memória. E a variável `user` contém uma "referência" para ele. -**When an object variable is copied -- the reference is copied, the object is not duplicated.** +**Quando uma variável com um objeto é copiada -- é a referência copiada, o objeto não é duplicado.** -If we imagine an object as a cabinet, then a variable is a key to it. Copying a variable duplicates the key, but not the cabinet itself. +Se imaginarmos um objeto como um fichário, então uma variável será uma chave (*a key*) para ele. Copiando uma variável duplica a chave (*the key*), não o próprio fichário. -For instance: +Por exemplo: ```js no-beautify let user = { name: "John" }; -let admin = user; // copy the reference +let admin = user; // copia a referência ``` -Now we have two variables, each one with the reference to the same object: +Agora, temos duas variáveis, e cada uma com a referência para o mesmo objeto: ![](variable-copy-reference.svg) -We can use any variable to access the cabinet and modify its contents: +Podemos utilizar qualquer das variáveis, para aceder ao fichário e alterar o seu conteúdo: ```js run let user = { name: 'John' }; @@ -520,46 +516,46 @@ let user = { name: 'John' }; let admin = user; *!* -admin.name = 'Pete'; // changed by the "admin" reference +admin.name = 'Pete'; // alterado através da referência em "admin" */!* -alert(*!*user.name*/!*); // 'Pete', changes are seen from the "user" reference +alert(*!*user.name*/!*); // 'Pete', as alterações também são visíveis por meio da referência em "user" ``` -The example above demonstrates that there is only one object. As if we had a cabinet with two keys and used one of them (`admin`) to get into it. Then, if we later use the other key (`user`) we would see changes. +O exemplo acima, demonstra que apenas existe um objecto. Como se tivéssemos um fichário com duas chaves, e usássemos uma delas (`admin`) para o aceder. E depois, se mais tarde usássemos a outra chave (`user`) poderíamos ver as alterações. -### Comparison by reference +### Comparação por referência -The equality `==` and strict equality `===` operators for objects work exactly the same. +Os operadores de igualdade `==` e de igualdade exata (*strict*) `===` para objetos funcionam exatamente da mesma forma. -**Two objects are equal only if they are the same object.** +**Dois objetos apenas são iguais se eles forem o mesmo objeto.** -For instance, two variables reference the same object, they are equal: +Por exemplo, duas variáveis referenciam o mesmo objeto, elas são iguais: ```js run let a = {}; -let b = a; // copy the reference +let b = a; // cópia por referência -alert( a == b ); // true, both variables reference the same object -alert( a === b ); // true +alert( a == b ); // true (verdadeiro), ambas as variáveis referenciam o mesmo objeto +alert( a === b ); // true (verdadeiro) ``` -And here two independent objects are not equal, even though both are empty: +E aqui, dois objetos independentes não são iguais, muito embora ambos sejam vazios: ```js run let a = {}; -let b = {}; // two independent objects +let b = {}; // dois objetos independentes -alert( a == b ); // false +alert( a == b ); // false (falso) ``` -For comparisons like `obj1 > obj2` or for a comparison against a primitive `obj == 5`, objects are converted to primitives. We'll study how object conversions work very soon, but to tell the truth, such comparisons are necessary very rarely and usually are a result of a coding mistake. +Para comparações como `obj1 > obj2` ou para uma comparação com um primitivo `obj == 5`, objetos são convertidos para primitivos. Estudaremos como funciona a conversão de objetos muito em breve, mas para dizer a verdade, tais comparações são muito raramente necessárias e são geralmente o resultado de um erro de código. -### Const object +### Objeto constante -An object declared as `const` *can* be changed. +Um objeto declarado com `const` *pode* ser alterado. -For instance: +Por exemplo: ```js run const user = { @@ -573,9 +569,9 @@ user.age = 25; // (*) alert(user.age); // 25 ``` -It might seem that the line `(*)` would cause an error, but no, there's totally no problem. That's because `const` fixes the value of `user` itself. And here `user` stores the reference to the same object all the time. The line `(*)` goes *inside* the object, it doesn't reassign `user`. +Parece que a linha `(*)` irá causar um erro, mas não, não há totalmente qualquer problema. Isso, porque `const` apenas fixa o valor de `user`. Então, aqui `user` armazena uma referência para um mesmo objeto pelo tempo todo. A linha `(*)` vai para *dentro* do objeto, não faz uma re-atribuição a `user`. -The `const` would give an error if we try to set `user` to something else, for instance: +A `const` produzirá um erro se tentarmos colocar em `user` qualquer outra coisa, por exemplo: ```js run const user = { @@ -583,26 +579,26 @@ const user = { }; *!* -// Error (can't reassign user) +// Erro (não é possível reatribuir a 'user') */!* user = { name: "Pete" }; ``` -...But what if we want to make constant object properties? So that `user.age = 25` would give an error. That's possible too. We'll cover it in the chapter . +...Mas, se quisermos tornar as propriedades do objeto constantes? Então, aí `user.age = 25` produzirá um erro. Isso, também é possível. Iremos cobrir isto no capítulo . -## Cloning and merging, Object.assign +## Clonar e fundir, Object.assign -So, copying an object variable creates one more reference to the same object. +Portanto, a cópia de uma variável de objeto cria mais uma referência para o mesmo objeto. -But what if we need to duplicate an object? Create an independent copy, a clone? +Mas, se quisermos duplicar um objecto? Criar uma cópia independente, um *clone*? -That's also doable, but a little bit more difficult, because there's no built-in method for that in JavaScript. Actually, that's rarely needed. Copying by reference is good most of the time. +Também se pode fazer, mas é um pouco mais difícil, porque não existe método incorporado (*built-in*) ao JavaScript para isso. Na verdade, isso raramente é necessário. A cópia por referência é a maior parte das vezes boa. -But if we really want that, then we need to create a new object and replicate the structure of the existing one by iterating over its properties and copying them on the primitive level. +Mas, se realmente quisermos isto, aí precisaremos de criar um novo objeto e replicar a estrutura do existente iterando pelas suas propriedades e copiando-as, digamos num nível primitivo. -Like this: +Desta forma: ```js run let user = { @@ -611,32 +607,32 @@ let user = { }; *!* -let clone = {}; // the new empty object +let clone = {}; // o novo objeto vazio -// let's copy all user properties into it +// copiemos todas as propriedades de 'user' para aquele for (let key in user) { clone[key] = user[key]; } */!* -// now clone is a fully independent clone -clone.name = "Pete"; // changed the data in it +// agora,'clone' é um clone completamente independente +clone.name = "Pete"; // altere dados nele -alert( user.name ); // still John in the original object +alert( user.name ); // contudo, ainda está 'John' no objeto original ``` -Also we can use the method [Object.assign](mdn:js/Object/assign) for that. +Podemos também empregar o método [Object.assign](mdn:js/Object/assign) para isso. -The syntax is: +A sintaxe é: ```js Object.assign(dest, [src1, src2, src3...]) ``` -- Arguments `dest`, and `src1, ..., srcN` (can be as many as needed) are objects. -- It copies the properties of all objects `src1, ..., srcN` into `dest`. In other words, properties of all arguments starting from the 2nd are copied into the 1st. Then it returns `dest`. +- Os argumentos `dest`, e `src1, ..., srcN` (que podem ser tantos quantos necessários) são objetos. +- Ele copia as propriedades de todos os objects `src1, ..., srcN` para `dest`. Por outras palavras, propriedades de todos os objetos, a começar pelo segundo, são copiadas para o primeiro. Depois, ele retorna `dest`. -For instance, we can use it to merge several objects into one: +Por exemplo, podemos utilizá-lo para fundir vários objetos num só: ```js let user = { name: "John" }; @@ -644,25 +640,25 @@ let permissions1 = { canView: true }; let permissions2 = { canEdit: true }; *!* -// copies all properties from permissions1 and permissions2 into user +// copia todas propriedades de 'permissions1' e 'permissions2' para 'user' Object.assign(user, permissions1, permissions2); */!* -// now user = { name: "John", canView: true, canEdit: true } +// agora, user = { name: "John", canView: true, canEdit: true } ``` -If the receiving object (`user`) already has the same named property, it will be overwritten: +Se, o objeto recetor (`user`) já tiver alguma propriedade com o mesmo nome, ela será substituída (*overwritten*): ```js let user = { name: "John" }; -// overwrite name, add isAdmin +// substitua ('overwrite') 'nome', e adicione 'isAdmin' Object.assign(user, { name: "Pete", isAdmin: true }); -// now user = { name: "Pete", isAdmin: true } +// agora, user = { name: "Pete", isAdmin: true } ``` -We also can use `Object.assign` to replace the loop for simple cloning: +Podemos também utilizar `Object.assign` para substituir o ciclo (*loop*) acima para uma clonagem simples: ```js let user = { @@ -675,11 +671,12 @@ let clone = Object.assign({}, user); */!* ``` -It copies all properties of `user` into the empty object and returns it. Actually, the same as the loop, but shorter. +Ele copia todas as propriedades de `user` para o objecto vazio e retorna este. Na verdade, é o mesmo laço (*loop*), mas mais curto. + +Até agora, assumimos que todas as propriedades de `user` são primitivas. Mas, propriedades podem ser referências para outros objetos. O que fazer nesse caso? -Until now we assumed that all properties of `user` are primitive. But properties can be references to other objects. What to do with them? +Como aqui: -Like this: ```js run let user = { name: "John", @@ -692,9 +689,10 @@ let user = { alert( user.sizes.height ); // 182 ``` -Now it's not enough to copy `clone.sizes = user.sizes`, because the `user.sizes` is an object, it will be copied by reference. So `clone` and `user` will share the same sizes: +Agora, não é suficiente efetuar a cópia `clone.sizes = user.sizes`, porque `user.sizes` é um objeto, e aí seria copiado por referência. Então, `clone` e `user` iriam partilhar a mesma propriedade "*sizes*": + +Deste modo: -Like this: ```js run let user = { name: "John", @@ -706,49 +704,48 @@ let user = { let clone = Object.assign({}, user); -alert( user.sizes === clone.sizes ); // true, same object +alert( user.sizes === clone.sizes ); // true (verdadeiro), é o mesmo objeto -// user and clone share sizes -user.sizes.width++; // change a property from one place -alert(clone.sizes.width); // 51, see the result from the other one +// 'user' e 'clone' partilham 'sizes' +user.sizes.width++; // altere uma propriedade num lugar +alert(clone.sizes.width); // 51, e verá o resultado a partir do outro ``` -To fix that, we should use the cloning loop that examines each value of `user[key]` and, if it's an object, then replicate its structure as well. That is called a "deep cloning". - -There's a standard algorithm for deep cloning that handles the case above and more complex cases, called the [Structured cloning algorithm](http://w3c.github.io/html/infrastructure.html#safe-passing-of-structured-data). In order not to reinvent the wheel, we can use a working implementation of it from the JavaScript library [lodash](https://lodash.com), the method is called [_.cloneDeep(obj)](https://lodash.com/docs#cloneDeep). - +Para corrigir isso, deveriamos empregar o laço (*loop*) para clonagem, que examina cada valor de `user[key]` e, se for um objeto, então também replica essa estrutura. Essa, é chamada de uma "clonagem profunda" ("*deep cloning*"). +Existe um algoritmo padrão (*standard*) para clonagem profunda (deep cloning), que trata tanto do caso acima como de mais complexos, chamado de [Structured cloning algorithm](http://w3c.github.io/html/infrastructure.html#safe-passing-of-structured-data) (algoritmo de clonagem de estruturas). Para não se reinventar a roda, poderemos utilizar uma implementação operacional do mesmo disponível na biblioteca (*library*) de JavaScript [lodash](https://lodash.com), o método é chamado [_.cloneDeep(obj)](https://lodash.com/docs#cloneDeep). -## Summary +## Sumário -Objects are associative arrays with several special features. +Objetos são *arrays* associativos (*associative arrays*), com várias funcionalidades especiais. -They store properties (key-value pairs), where: -- Property keys must be strings or symbols (usually strings). -- Values can be of any type. +Eles armazenam propriedades em pares chave-valor, onde: +- As chaves das propriedades devem ser *strings* ou símbolos (geralmente *strings*). +- Valores podem ser de qualquer tipo. -To access a property, we can use: -- The dot notation: `obj.property`. -- Square brackets notation `obj["property"]`. Square brackets allow to take the key from a variable, like `obj[varWithKey]`. +Para aceder a uma propriedade, podemos utilizar: +- A notação por ponto: `obj.property`. +- A notação por parênteses retos `obj["property"]`. Os parênteses retos permitem receber a chave de uma variável, como por exemplo `obj[varWithKey]`. -Additional operators: -- To delete a property: `delete obj.prop`. -- To check if a property with the given key exists: `"key" in obj`. -- To iterate over an object: `for (let key in obj)` loop. +Operadores adicionais: +- Para remover uma propriedade: `delete obj.prop`. +- Para verificar se uma propriedade com uma dada chave existe: `"key" in obj`. +- Para iterar sobre um objeto: o ciclo `for (let key in obj)`. -Objects are assigned and copied by reference. In other words, a variable stores not the "object value", but a "reference" (address in memory) for the value. So copying such a variable or passing it as a function argument copies that reference, not the object. All operations via copied references (like adding/removing properties) are performed on the same single object. +Objetos são atribuidos e copiados por referência. Por outras palavras, uma variável não armazena o "valor do objeto", mas uma "referência" (endereço em memória) do valor. Assim, copiar tal variável ou passá-la como argumento de uma função copia tal referência, não o objeto. Todas as operações sobre cópias de referências (como adicionar/remover propriedades) são executadas sobre um mesmo único objeto. -To make a "real copy" (a clone) we can use `Object.assign` or [_.cloneDeep(obj)](https://lodash.com/docs#cloneDeep). + Para efetuar uma "verdadeira cópia" (um clone), podemos utilizar `Object.assign` ou [_.cloneDeep(obj)](https://lodash.com/docs#cloneDeep). -What we've studied in this chapter is called a "plain object", or just `Object`. +O que estudámos neste capítulo é o chamado "objeto simples" ("*plain object*"), ou simplesmente `Objeto`. -There are many other kinds of objects in JavaScript: +Existem muitos outros tipos de objetos em JavaScript: -- `Array` to store ordered data collections, -- `Date` to store the information about the date and time, -- `Error` to store the information about an error. -- ...And so on. +- `Array` para armazenar coleções de dados ordenadas, +- `Date` para armazenar informação sobre data e tempo, +- `Error` para armazenar informação sobre um erro. +- ...E outros mais. -They have their special features that we'll study later. Sometimes people say something like "Array type" or "Date type", but formally they are not types of their own, but belong to a single "object" data type. And they extend it in various ways. +Eles têm as suas funcionalidades especiais, que estudaremos mais adiante. Por vezes, pessoas dizem algo como "o tipo +Array" ou "o tipo Data" (*Date*), mas formalmente eles não são própriamente tipos, mas pertencem a um único tipo de dados "objeto". E o extendem de várias formas. -Objects in JavaScript are very powerful. Here we've just scratched the surface of a topic that is really huge. We'll be closely working with objects and learning more about them in further parts of the tutorial. +Objetos em JavaScript são muito poderosos. Aqui, apenas tocámos na superfície de um realmente amplo tópico. Iremos, mais especificamente, trabalhar e aprender sobre objetos em futuras partes do tutorial. diff --git a/1-js/04-object-basics/index.md b/1-js/04-object-basics/index.md index d2387aafa..991117d25 100644 --- a/1-js/04-object-basics/index.md +++ b/1-js/04-object-basics/index.md @@ -1 +1 @@ -# Objects: the basics +# Objetos: o básico From e788cff1378d6dcecdfd267c879df2efc0b85d68 Mon Sep 17 00:00:00 2001 From: odsantos Date: Tue, 22 Oct 2019 06:28:04 +0100 Subject: [PATCH 2/8] Revert "translate '01-object' directory files" This reverts commit f3fb7d2927a16e702ac7683957ff2981c86d31c5. --- .../01-object/2-hello-object/solution.md | 2 + .../01-object/2-hello-object/task.md | 14 +- .../01-object/3-is-empty/_js.view/solution.js | 2 +- .../01-object/3-is-empty/_js.view/test.js | 4 +- .../01-object/3-is-empty/solution.md | 2 +- .../01-object/3-is-empty/task.md | 13 +- .../01-object/4-const-object/solution.md | 10 +- .../01-object/4-const-object/task.md | 6 +- .../01-object/5-sum-object/task.md | 8 +- .../8-multiply-numeric/_js.view/source.js | 6 +- .../8-multiply-numeric/_js.view/test.js | 8 +- .../01-object/8-multiply-numeric/task.md | 20 +- 1-js/04-object-basics/01-object/article.md | 473 +++++++++--------- 1-js/04-object-basics/index.md | 2 +- 14 files changed, 289 insertions(+), 281 deletions(-) diff --git a/1-js/04-object-basics/01-object/2-hello-object/solution.md b/1-js/04-object-basics/01-object/2-hello-object/solution.md index dff006076..60083b963 100644 --- a/1-js/04-object-basics/01-object/2-hello-object/solution.md +++ b/1-js/04-object-basics/01-object/2-hello-object/solution.md @@ -1,4 +1,5 @@ + ```js let user = {}; user.name = "John"; @@ -6,3 +7,4 @@ user.surname = "Smith"; user.name = "Pete"; delete user.name; ``` + diff --git a/1-js/04-object-basics/01-object/2-hello-object/task.md b/1-js/04-object-basics/01-object/2-hello-object/task.md index c0e296444..2841a058f 100644 --- a/1-js/04-object-basics/01-object/2-hello-object/task.md +++ b/1-js/04-object-basics/01-object/2-hello-object/task.md @@ -2,13 +2,13 @@ importance: 5 --- -# Olá, objeto +# Hello, object -Escreva o código, uma ação por linha: +Write the code, one line for each action: -1. Crie um objeto vazio (*empty object*) `user`. -2. Adicione a propriedade `name` com o valor `John`. -3. Adicione a propriedade `surname` com o valor `Smith`. -4. Altere o valor de `name` para `Pete`. -5. Remova a propriedade `name` do objeto. +1. Create an empty object `user`. +2. Add the property `name` with the value `John`. +3. Add the property `surname` with the value `Smith`. +4. Change the value of the `name` to `Pete`. +5. Remove the property `name` from the object. diff --git a/1-js/04-object-basics/01-object/3-is-empty/_js.view/solution.js b/1-js/04-object-basics/01-object/3-is-empty/_js.view/solution.js index ca7dc324e..db3283e49 100644 --- a/1-js/04-object-basics/01-object/3-is-empty/_js.view/solution.js +++ b/1-js/04-object-basics/01-object/3-is-empty/_js.view/solution.js @@ -1,6 +1,6 @@ function isEmpty(obj) { for (let key in obj) { - // se o laço começou, existe uma propriedade + // if the loop has started, there is a property return false; } return true; diff --git a/1-js/04-object-basics/01-object/3-is-empty/_js.view/test.js b/1-js/04-object-basics/01-object/3-is-empty/_js.view/test.js index 400577698..4db5efabe 100644 --- a/1-js/04-object-basics/01-object/3-is-empty/_js.view/test.js +++ b/1-js/04-object-basics/01-object/3-is-empty/_js.view/test.js @@ -1,9 +1,9 @@ describe("isEmpty", function() { - it("retorna verdadeiro para um objeto vazio", function() { + it("returns true for an empty object", function() { assert.isTrue(isEmpty({})); }); - it("retorna falso se uma propriedade existir", function() { + it("returns false if a property exists", function() { assert.isFalse(isEmpty({ anything: false })); diff --git a/1-js/04-object-basics/01-object/3-is-empty/solution.md b/1-js/04-object-basics/01-object/3-is-empty/solution.md index 6c328fc39..b876973b5 100644 --- a/1-js/04-object-basics/01-object/3-is-empty/solution.md +++ b/1-js/04-object-basics/01-object/3-is-empty/solution.md @@ -1 +1 @@ -Simplemente, percorra (*loop over*) o objeto e imediatamente `return false` se pelo menos houver uma propriedade. +Just loop over the object and `return false` immediately if there's at least one property. diff --git a/1-js/04-object-basics/01-object/3-is-empty/task.md b/1-js/04-object-basics/01-object/3-is-empty/task.md index a499e6eb7..c438d36a2 100644 --- a/1-js/04-object-basics/01-object/3-is-empty/task.md +++ b/1-js/04-object-basics/01-object/3-is-empty/task.md @@ -2,18 +2,19 @@ importance: 5 --- -# Verifique por vazio (*emptiness*) +# Check for emptiness -Escreva a função `isEmpty(obj)`, que retorna `true` se o objeto não tiver propriedades, e `false` caso contrário. +Write the function `isEmpty(obj)` which returns `true` if the object has no properties, `false` otherwise. + +Should work like that: -Deve assim funcionar: ```js let schedule = {}; -alert( isEmpty(schedule) ); // verdadeiro +alert( isEmpty(schedule) ); // true -schedule["8:30"] = "levante-se"; +schedule["8:30"] = "get up"; -alert( isEmpty(schedule) ); // falso +alert( isEmpty(schedule) ); // false ``` diff --git a/1-js/04-object-basics/01-object/4-const-object/solution.md b/1-js/04-object-basics/01-object/4-const-object/solution.md index 9cb150373..f73c2f92b 100644 --- a/1-js/04-object-basics/01-object/4-const-object/solution.md +++ b/1-js/04-object-basics/01-object/4-const-object/solution.md @@ -1,8 +1,8 @@ -Com certeza, funciona, sem problemas. +Sure, it works, no problem. -A `const` apenas protege a própria variável contra alterações. +The `const` only protects the variable itself from changing. -Por outras palavras, `user` armazena uma referência ao objeto. E não pode ser alterada. Mas, o conteúdo do objeto pode. +In other words, `user` stores a reference to the object. And it can't be changed. But the content of the object can. ```js run const user = { @@ -10,10 +10,10 @@ const user = { }; *!* -// funciona +// works user.name = "Pete"; */!* -// erro +// error user = 123; ``` diff --git a/1-js/04-object-basics/01-object/4-const-object/task.md b/1-js/04-object-basics/01-object/4-const-object/task.md index a0a1709dc..a9aada631 100644 --- a/1-js/04-object-basics/01-object/4-const-object/task.md +++ b/1-js/04-object-basics/01-object/4-const-object/task.md @@ -2,9 +2,9 @@ importance: 5 --- -# Objetos constantes? +# Constant objects? -É possível alterar um objeto declarado com `const`? O que acha? +Is it possible to change an object declared with `const`? What do you think? ```js const user = { @@ -12,7 +12,7 @@ const user = { }; *!* -// isto funciona? +// does it work? user.name = "Pete"; */!* ``` diff --git a/1-js/04-object-basics/01-object/5-sum-object/task.md b/1-js/04-object-basics/01-object/5-sum-object/task.md index b0caee202..7e3e048d0 100644 --- a/1-js/04-object-basics/01-object/5-sum-object/task.md +++ b/1-js/04-object-basics/01-object/5-sum-object/task.md @@ -2,9 +2,9 @@ importance: 5 --- -# Soma das propriedades de um objeto +# Sum object properties -Temos um objeto armazenando salários da nossa equipa: +We have an object storing salaries of our team: ```js let salaries = { @@ -14,6 +14,6 @@ let salaries = { } ``` -Escreva o código para somar todos os salários e armazenar na variável `sum`. Para o exemplo acima, deverá ser `390`. +Write the code to sum all salaries and store in the variable `sum`. Should be `390` in the example above. -Se `salaries` for vazio, então o resultado deve ser `0`. \ No newline at end of file +If `salaries` is empty, then the result must be `0`. \ No newline at end of file diff --git a/1-js/04-object-basics/01-object/8-multiply-numeric/_js.view/source.js b/1-js/04-object-basics/01-object/8-multiply-numeric/_js.view/source.js index f2ffe4901..a02b1e1cb 100644 --- a/1-js/04-object-basics/01-object/8-multiply-numeric/_js.view/source.js +++ b/1-js/04-object-basics/01-object/8-multiply-numeric/_js.view/source.js @@ -1,17 +1,17 @@ let menu = { width: 200, height: 300, - title: "O meu menu" + title: "My menu" }; function multiplyNumeric(obj) { - /* o seu código */ + /* your code */ } multiplyNumeric(menu); -alert( "largura do menu=" + menu.width + " altura=" + menu.height + " título=" + menu.title ); +alert( "menu width=" + menu.width + " height=" + menu.height + " title=" + menu.title ); diff --git a/1-js/04-object-basics/01-object/8-multiply-numeric/_js.view/test.js b/1-js/04-object-basics/01-object/8-multiply-numeric/_js.view/test.js index 2ba28f769..064e5414f 100644 --- a/1-js/04-object-basics/01-object/8-multiply-numeric/_js.view/test.js +++ b/1-js/04-object-basics/01-object/8-multiply-numeric/_js.view/test.js @@ -1,17 +1,17 @@ describe("multiplyNumeric", function() { - it("multiplica todas as propriedades numéricas por 2", function() { + it("multiplies all numeric properties by 2", function() { let menu = { width: 200, height: 300, - title: "O meu menu" + title: "My menu" }; let result = multiplyNumeric(menu); assert.equal(menu.width, 400); assert.equal(menu.height, 600); - assert.equal(menu.title, "O meu menu"); + assert.equal(menu.title, "My menu"); }); - it("não retorna nada", function() { + it("returns nothing", function() { assert.isUndefined( multiplyNumeric({}) ); }); diff --git a/1-js/04-object-basics/01-object/8-multiply-numeric/task.md b/1-js/04-object-basics/01-object/8-multiply-numeric/task.md index 54fa7fceb..33eb89220 100644 --- a/1-js/04-object-basics/01-object/8-multiply-numeric/task.md +++ b/1-js/04-object-basics/01-object/8-multiply-numeric/task.md @@ -2,30 +2,32 @@ importance: 3 --- -# Multiplica as propriedades numéricas por 2 +# Multiply numeric properties by 2 -Crie uma função `multiplyNumeric(obj)` que multiplica todas as proriedades numéricas de `obj` por `2`. +Create a function `multiplyNumeric(obj)` that multiplies all numeric properties of `obj` by `2`. -Por exemplo: +For instance: ```js -// antes da chamada +// before the call let menu = { width: 200, height: 300, - title: "O meu menu" + title: "My menu" }; multiplyNumeric(menu); -// depois da chamada +// after the call menu = { width: 400, height: 600, - title: "O meu menu" + title: "My menu" }; ``` -Por favor, note que `multiplyNumeric` não precisa de retornar nada. Deve modificar o próprio objecto. +Please note that `multiplyNumeric` does not need to return anything. It should modify the object in-place. + +P.S. Use `typeof` to check for a number here. + -P.S. Use `typeof` para verificar por um número aqui. diff --git a/1-js/04-object-basics/01-object/article.md b/1-js/04-object-basics/01-object/article.md index baba98e3a..00706750c 100644 --- a/1-js/04-object-basics/01-object/article.md +++ b/1-js/04-object-basics/01-object/article.md @@ -1,60 +1,60 @@ -# Objetos +# Objects -Como sabemos, pelo capítulo , existem sete tipos de dados em JavaScript. Seis deles são chamados de "primitivos", porque os seus valores apenas contêm uma única coisa (seja ela uma cadeia-de-carateres [*string*], um número, ou o que for). +As we know from the chapter , there are seven data types in JavaScript. Six of them are called "primitive", because their values contain only a single thing (be it a string or a number or whatever). -Em contraste, objetos são empregues para armazenar por meio de uma chave, coleções de vários dados e entidades mais complexas. Em JavaScript, objetos penetram em quase todos os aspetos da linguagem. Portanto, devemos primeiro compreendê-los antes de nos envolvermos detalhadamente em algo mais. +In contrast, objects are used to store keyed collections of various data and more complex entities. In JavaScript, objects penetrate almost every aspect of the language. So we must understand them first before going in-depth anywhere else. -Um objeto pode ser criado por chavetas `{…}`, com uma lista opcional de *propriedades*. Uma propriedade é um par "key: value" (chave: valor), onde `key` é uma *string* (também chamada de "nome da propriedade"), e `value` pode ser qualquer coisa. +An object can be created with figure brackets `{…}` with an optional list of *properties*. A property is a "key: value" pair, where `key` is a string (also called a "property name"), and `value` can be anything. -Podemos imaginar um objeto como um fichário com ficheiros assinados. Cada peça de informação, é armazenada no seu ficheiro ligada a uma chave. É fácil encontrar um ficheiro através do seu nome, ou adicionar/remover um ficheiro. +We can imagine an object as a cabinet with signed files. Every piece of data is stored in its file by the key. It's easy to find a file by its name or add/remove a file. ![](object.svg) -Um objeto vazio ("fichário vazio"), pode ser criado por uma de duas sintaxes: +An empty object ("empty cabinet") can be created using one of two syntaxes: ```js -let user = new Object(); // sintaxe de "construtor de objetos" -let user = {}; // sintaxe de "objeto literal" +let user = new Object(); // "object constructor" syntax +let user = {}; // "object literal" syntax ``` ![](object-user-empty.svg) -Geralmente, são utilizadas as chavetas `{...}`. Essa declaração é chamada de *objeto literal*. +Usually, the figure brackets `{...}` are used. That declaration is called an *object literal*. -## Literais e propriedades +## Literals and properties -Podemos imediatamente colocar algumas propriedades dentro das `{...}` como pares "chave: valor" (*key: value*): +We can immediately put some properties into `{...}` as "key: value" pairs: ```js -let user = { // um objeto - name: "John", // na chave "name" armazene o valor "John" - age: 30 // na chave "age" armazene o valor 30 +let user = { // an object + name: "John", // by key "name" store value "John" + age: 30 // by key "age" store value 30 }; ``` -Uma propriedade, tem uma chave (*key* - também conhecida por "nome" ou "identificador") antes dos dois-pontos `":"` e um valor à sua direita. +A property has a key (also known as "name" or "identifier") before the colon `":"` and a value to the right of it. -No objeto `user`, existem duas propriedades: +In the `user` object, there are two properties: -1. A primeira, tem o nome `"name"` e o valor `"John"`. -2. A segunda, tem o nome `"age"` e o valor `30`. +1. The first property has the name `"name"` and the value `"John"`. +2. The second one has the name `"age"` and the value `30`. -O objeto `user` resultante, pode ser imaginado como um fichário com dois ficheiros assinados com as etiquetas "*name*" e "*age*". +The resulting `user` object can be imagined as a cabinet with two signed files labeled "name" and "age". ![user object](object-user.svg) -Podemos adicionar, remover e ler ficheiros dele a qualquer altura. +We can add, remove and read files from it any time. -Valores de propriedades podem ser acedidos usando a notação por ponto (*dot notation*): +Property values are accessible using the dot notation: ```js -// obtenha os campos do objeto: +// get fields of the object: alert( user.name ); // John alert( user.age ); // 30 ``` -O valor pode ser de qualquer tipo. Vamos adicionar um booleano: +The value can be of any type. Let's add a boolean one: ```js user.isAdmin = true; @@ -62,7 +62,7 @@ user.isAdmin = true; ![user object 2](object-user-isadmin.svg) -Para remover uma propriedade, podemos usar o operador `delete`: +To remove a property, we can use `delete` operator: ```js delete user.age; @@ -70,70 +70,69 @@ delete user.age; ![user object 3](object-user-delete.svg) -Podemos também usar nomes de propriedades com múltiplas palavras, mas aí eles têm de estar entre aspas: +We can also use multiword property names, but then they must be quoted: ```js let user = { name: "John", age: 30, - "likes birds": true // "likes birds" ("gosta de pássaros") - o nome de propriedade com múltiplas palavras tem de estar entre aspas + "likes birds": true // multiword property name must be quoted }; ``` ![](object-user-props.svg) -A última propriedade da lista pode terminar com uma vírgula: +The last property in the list may end with a comma: ```js let user = { name: "John", age: 30*!*,*/!* } ``` +That is called a "trailing" or "hanging" comma. Makes it easier to add/remove/move around properties, because all lines become alike. -Esta é chamada de vírgula à direita (*trailing comma*) ou "vírgula pendurada" (*hanging comma*). Ela facilita o adicionar/remover/mover propriedades, porque todas as linhas serão semelhantes (as propriedades são separadas por vírgulas). +## Square brackets -## Parênteses retos - -Para propriedades com múltiplas palavras, o acesso por ponto não funciona: +For multiword properties, the dot access doesn't work: ```js run -// isto daria um erro de sintaxe +// this would give a syntax error user.likes birds = true ``` -Isto, porque o ponto requere que a chave (*key*) seja um identificador de variável válido. Isto é: sem espaços e outras restrições. +That's because the dot requires the key to be a valid variable identifier. That is: no spaces and other limitations. -Existe uma alternativa, a "notação por parênteses retos", que funciona com qualquer *string* (cadeia-de-carateres): +There's an alternative "square bracket notation" that works with any string: ```js run let user = {}; -// cria +// set user["likes birds"] = true; -// lê -alert(user["likes birds"]); // true ('verdadeiro') +// get +alert(user["likes birds"]); // true -// remove +// delete delete user["likes birds"]; ``` -Agora, tudo está bem. Por favor, verifique se a *string* dentro dos parênteses retos está própriamente encerrada entre aspas (qualquer tipo de aspas serve). +Now everything is fine. Please note that the string inside the brackets is properly quoted (any type of quotes will do). -Os parênteses retos, também fornecem uma forma de se obter o nome de uma propriedade como resultado de uma expressão -- em vez de uma *string* literal -- como a partir de uma variável, a exemplo: +Square brackets also provide a way to obtain the property name as the result of any expression -- as opposed to a literal string -- like from a variable as follows: ```js let key = "likes birds"; -// o mesmo que 'user["likes birds"] = true;' +// same as user["likes birds"] = true; user[key] = true; ``` -Aqui, a variável `key` pode ser calculada em tempo de execução (*run-time*) ou depender de uma entrada pelo utilizador (*user input*). E depois a utilizamos para aceder à propriedade. Isso, dá-nos um grande grau de flexibilidade. +Here, the variable `key` may be calculated at run-time or depend on the user input. And then we use it to access the property. That gives us a great deal of flexibility. The dot notation cannot be used in a similar way. -Por exemplo: +For instance: ```js run let user = { @@ -141,13 +140,15 @@ let user = { age: 30 }; -let key = prompt("O que quer saber acerca do utilizador?", "name"); +let key = prompt("What do you want to know about the user?", "name"); -// aceda à variável -alert( user[key] ); // John (se a entrada tiver sido "name") +// access by variable +alert( user[key] ); // John (if enter "name") ``` -A notação por ponto não pode ser usada de forma semelhante: +<<<<<<< HEAD +======= +The dot notation cannot be used in a similar way: ```js run let user = { @@ -158,41 +159,42 @@ let user = { let key = "name"; alert( user.key ) // undefined ``` +>>>>>>> 852ee189170d9022f67ab6d387aeae76810b5923 -### Propriedades computadas +### Computed properties -Podemos utilizar os parênteses retos num object literal. Chamam-se de *propriedades computadas*. +We can use square brackets in an object literal. That's called *computed properties*. -Por exemplo: +For instance: ```js run -let fruit = prompt("Que fruta comprar?", "apple"); +let fruit = prompt("Which fruit to buy?", "apple"); let bag = { *!* - [fruit]: 5, // o nome da propriedade é obtido por meio da variável 'fruit' + [fruit]: 5, // the name of the property is taken from the variable fruit */!* }; alert( bag.apple ); // 5 if fruit="apple" ``` -O significado de uma propriedade computada é simples: `[fruit]` diz que o nome da propriedade é obtido por meio de `fruit`. +The meaning of a computed property is simple: `[fruit]` means that the property name should be taken from `fruit`. -Assim, se um visitante inserir `"apple"`, `bag` se tornará em `{apple: 5}`. +So, if a visitor enters `"apple"`, `bag` will become `{apple: 5}`. -Essencialmente, isso é o mesmo que: +Essentially, that works the same as: ```js run -let fruit = prompt("Que fruta comprar?", "apple"); +let fruit = prompt("Which fruit to buy?", "apple"); let bag = {}; -// obtenha o nome da propriedade por meio da variável fruit +// take property name from the fruit variable bag[fruit] = 5; ``` -...Mas, tem uma melhor apresentação. +...But looks nicer. -Podemos usar expressões mais complexas dentro dos parênteses retos: +We can use more complex expressions inside square brackets: ```js let fruit = 'apple'; @@ -201,14 +203,16 @@ let bag = { }; ``` -Parênteses retos, são mais poderosos que a notação por ponto. Eles permitem quaisquer nomes de propriedades e variáveis. Mas, eles também envolvem mais trabalho para escrever. +Square brackets are much more powerful than the dot notation. They allow any property names and variables. But they are also more cumbersome to write. + +So most of the time, when property names are known and simple, the dot is used. And if we need something more complex, then we switch to square brackets. + -Assim, a maior parte as vezes, quando nomes de propriedades são conhecidos e simples, o ponto é utilizado. E, se precisarmos de algo mais complexo, mudamos para os parênteses retos. ````smart header="Reserved words are allowed as property names" -Uma variável, não pode ter um nome igual a uma das palavras reservadas ('keywords') da linguagem, como "for", "let", "return" etc. +A variable cannot have a name equal to one of language-reserved words like "for", "let", "return" etc. -Mas, para uma propriedade de um objeto, não existe tal restrição. Qualquer nome é aceitável: +But for an object property, there's no such restriction. Any name is fine: ```js run let obj = { @@ -220,27 +224,28 @@ let obj = { alert( obj.for + obj.let + obj.return ); // 6 ``` -Basicamente, qualquer nome é permitido, mas existe um especial: `"__proto__"`, que tem um tratamento particular por razões históricas. Por exemplo, a ele não podemos atribuir um valor não-objeto: +Basically, any name is allowed, but there's a special one: `"__proto__"` that gets special treatment for historical reasons. For instance, we can't set it to a non-object value: ```js run let obj = {}; obj.__proto__ = 5; -alert(obj.__proto__); // [object Object], não resultou como esperado +alert(obj.__proto__); // [object Object], didn't work as intended ``` -Como vemos pelo código, a atribuição do primitivo `5` é ignorada. +As we see from the code, the assignment to a primitive `5` is ignored. -Isso, pode se tornar numa fonte de erros ('bugs') e até de vulnerabilidades, se pretendermos armazenar pares chave-valor arbitrários num objeto, e permitir a um visitante especificar as chaves ('keys'). +That can become a source of bugs and even vulnerabilities if we intend to store arbitrary key-value pairs in an object, and allow a visitor to specify the keys. -Nesse caso, o the visitante pode escolher "__proto__" como chave, e a lógica de atribuição estará arruinada (como se mostra acima). +In that case the visitor may choose "__proto__" as the key, and the assignment logic will be ruined (as shown above). -Existe uma forma de fazer os objetos tratarem `__proto__` como uma propriedade regular, que analisaremos mais adiante, mas primeiro precisamos de saber mais sobre objetos. -Existe também outra estrutura de dados [Map](info:map-set-weakmap-weakset), que aprenderemos no capítulo , que suporta chaves arbitrárias. +There is a way to make objects treat `__proto__` as a regular property, which we'll cover later, but first we need to know more about objects. +There's also another data structure [Map](info:map-set-weakmap-weakset), that we'll learn in the chapter , which supports arbitrary keys. ```` -## Abreviação do valor da propriedade -Em código real, frequentemente empregamos variáveis semelhantes a valores como nomes de propriedades. +## Property value shorthand + +In real code we often use existing variables as values for property names. For instance: @@ -249,7 +254,7 @@ function makeUser(name, age) { return { name: name, age: age - // ...outras propriedades + // ...other properties }; } @@ -257,102 +262,103 @@ let user = makeUser("John", 30); alert(user.name); // John ``` -No exemplo acima, propriedades têm os mesmos nomes que as variáveis. O caso prático (*use-case*) de construir uma propriedade com base numa variável é tão comum, que existe uma especial *abreviação do valor da propriedade* (*property value shorthand*) para a tornar mais curta. +In the example above, properties have the same names as variables. The use-case of making a property from a variable is so common, that there's a special *property value shorthand* to make it shorter. -Em vez de `name:name`, podemos simplesmente escrever `name`, como abaixo: +Instead of `name:name` we can just write `name`, like this: ```js function makeUser(name, age) { *!* return { - name, // o mesmo que name: name - age // o mesmo que age: age + name, // same as name: name + age // same as age: age // ... }; */!* } ``` -Podemos empregar ambas, as propriedades normais e as abreviações (*shorthands*) no mesmo objeto: +We can use both normal properties and shorthands in the same object: ```js let user = { - name, // o mesmo que name:name + name, // same as name:name age: 30 }; ``` -## Verificação de existência +## Existence check -Uma particularidade notável de objetos, é que é possível aceder a qualquer propriedade. Não haverá erro se a propriedade não existir! Aceder a uma propriedade não-existente apenas retorna `undefined`. Ela, fornece uma forma muito comum de testar se a propriedade existe -- aceda, e compare o resultado com *undefined*: +A notable objects feature is that it's possible to access any property. There will be no error if the property doesn't exist! Accessing a non-existing property just returns `undefined`. It provides a very common way to test whether the property exists -- to get it and compare vs undefined: ```js run let user = {}; -alert( user.noSuchProperty === undefined ); // true, significa "propriedade não existente" (no such property) +alert( user.noSuchProperty === undefined ); // true means "no such property" ``` -Também existe um operador especial, `"in"`, para verificar a existência de uma propriedade. - -A sintaxe é: +There also exists a special operator `"in"` to check for the existence of a property. +The syntax is: ```js "key" in object ``` -Por exemplo: +For instance: ```js run let user = { name: "John", age: 30 }; -alert( "age" in user ); // true (verdadeiro), 'user.age' existe -alert( "blabla" in user ); // false (falso), 'user.blabla' não existe +alert( "age" in user ); // true, user.age exists +alert( "blabla" in user ); // false, user.blabla doesn't exist ``` -Por favor, note que no lado esquerdo de `in` deve existir um *nome de propriedade*. Geralmente, é uma *string* entre aspas. +Please note that on the left side of `in` there must be a *property name*. That's usually a quoted string. -Se omitirmos as aspas, isso terá o significado de uma variável contendo o atual nome a ser testado. Por exemplo: +If we omit quotes, that would mean a variable containing the actual name will be tested. For instance: ```js run let user = { age: 30 }; let key = "age"; -alert( *!*key*/!* in user ); // true (verdadeiro), recebe o nome por meio de 'key' e procura por tal propriedade +alert( *!*key*/!* in user ); // true, takes the name from key and checks for such property ``` -````smart header="Using "in" for properties that store "undefined"" -Geralmente, a comparação exata ('strict') para a verificação `"=== undefined"` funciona bem. Mas, existe um caso especial em que falha. Contudo, `"in"` funciona corretamente. +````smart header="Using \"in\" for properties that store `undefined`" +Usually, the strict comparison `"=== undefined"` check works fine. But there's a special case when it fails, but `"in"` works correctly. -É quando uma propriedade de um objeto existe, mas possui `undefined` nela armazenado: +It's when an object property exists, but stores `undefined`: ```js run let obj = { test: undefined }; -alert( obj.test ); // exibe 'undefined', então - tal propriedade não existe? +alert( obj.test ); // it's undefined, so - no such property? -alert( "test" in obj ); // true (verdadeiro), a propriedade na realidade existe! +alert( "test" in obj ); // true, the property does exist! ``` -No código acima, a propriedade `obj.test` tecnicamente existe. Deste modo, o operador `in` funciona corretamente. -Situações como esta muito raramente ocorrem, porque `undefined` não é usualmente atribuido. Em geral, empregamos `null` para valores "desconhecidos" ou "vazios". Deste modo, o operador `in` é um convidado exótico na codificação. +In the code above, the property `obj.test` technically exists. So the `in` operator works right. + +Situations like this happen very rarely, because `undefined` is usually not assigned. We mostly use `null` for "unknown" or "empty" values. So the `in` operator is an exotic guest in the code. ```` -## O laço "for..in" -Para navegar por todas as chaves (*keys*) de um objeto, existe uma forma especial de laço (*loop*): `for..in`. Esta, é uma construção completamente diferente da do `for(;;)`, que estudámos antes. +## The "for..in" loop -A sintaxe: +To walk over all keys of an object, there exists a special form of the loop: `for..in`. This is a completely different thing from the `for(;;)` construct that we studied before. + +The syntax: ```js for (key in object) { - // executa o corpo do laço, por cada chave (key) de entre as propriedades do objeto + // executes the body for each key among object properties } ``` -Por exemplo, vamos imprimir todas propriedades de `user`: +For instance, let's output all properties of `user`: ```js run let user = { @@ -362,32 +368,33 @@ let user = { }; for (let key in user) { - // key (chave) - alert( key ); // 'name', 'age', isAdmin' - // valor por chave (key) + // keys + alert( key ); // name, age, isAdmin + // values for the keys alert( user[key] ); // John, 30, true } ``` -Note, que todas as construções "for" permitem-nos declarar a variável do laço dentro do ciclo (*loop*), como `let key` aqui. +Note that all "for" constructs allow us to declare the looping variable inside the loop, like `let key` here. + +Also, we could use another variable name here instead of `key`. For instance, `"for (let prop in obj)"` is also widely used. -De igual modo, poderíamos usar aqui um nome de variável differente de `key`. Por exemplo, `"for (let prop in obj)"` também é largamente utilizado. -### Ordenado como um objeto +### Ordered like an object -Os objetos são ordenados? Por outras palavras, se percorrermos um objeto com um laço, será que obtemos todas as propriedades pela mesma ordem em que foram adicionadas? Poderemos confiar nisso? +Are objects ordered? In other words, if we loop over an object, do we get all properties in the same order they were added? Can we rely on this? -A curta resposta é: "ordenados de um modo especial" - propriedades inteiras são ordenadas de forma crescente, outras aparecem na ordem em que foram criadas. Detalhes a seguir. +The short answer is: "ordered in a special fashion": integer properties are sorted, others appear in creation order. The details follow. -Como exemplo, considermos um objeto com indicativos telefónicos de países: +As an example, let's consider an object with the phone codes: ```js run let codes = { - "49": "Alemanha", - "41": "Suíça", - "44": "Grã Bretanha", + "49": "Germany", + "41": "Switzerland", + "44": "Great Britain", // .., - "1": "EUA" + "1": "USA" }; *!* @@ -397,59 +404,56 @@ for (let code in codes) { */!* ``` -O objeto, pode ser empregue como sugestão de uma lista de opções para o utilizador. Se, estivermos a construir um *site* maioritariamente para uma audiência Alemã, então provavelmente queremos `49` como o primeiro. +The object may be used to suggest a list of options to the user. If we're making a site mainly for German audience then we probably want `49` to be the first. -Mas, ao correr o código, vemos uma imagem totalmente diferente: +But if we run the code, we see a totally different picture: -- EUA (1) vem em primeiro lugar, -- depois a Suiça (41), e assim por adiante. +- USA (1) goes first +- then Switzerland (41) and so on. -Os indicativos telefónicos, são ordenados por ordem ascendente, porque são inteiros. Por isso, vemos `1, 41, 44, 49`. +The phone codes go in the ascending sorted order, because they are integers. So we see `1, 41, 44, 49`. ````smart header="Integer properties? What's that?" -O termo "propriedade inteira" aqui, significa que uma *string* pode ser convertida para inteiro ('integer') e, de volta reconvertida sem qualquer alteração. +The "integer property" term here means a string that can be converted to-and-from an integer without a change. -Assim, "49" é um nome de propriedade inteiro porque, ao ser transformado num número inteiro e de volta reconvertido, continua o mesmo. Mas, "+49" e "1.2" não são: +So, "49" is an integer property name, because when it's transformed to an integer number and back, it's still the same. But "+49" and "1.2" are not: ```js run -// Math.trunc é uma função incorporada (*built-in function*) que remove a parte decimal - -alert( String(Math.trunc(Number("49"))) ); // "49", inalterado ⇒ propriedade inteira - -alert( String(Math.trunc(Number("+49"))) ); // "49", não o mesmo que "+49" ⇒ não é uma propriedade inteira - -alert( String(Math.trunc(Number("1.2"))) ); // "1", não o mesmo que "1.2" ⇒ não é uma propriedade inteira +// Math.trunc is a built-in function that removes the decimal part +alert( String(Math.trunc(Number("49"))) ); // "49", same, integer property +alert( String(Math.trunc(Number("+49"))) ); // "49", not same "+49" ⇒ not integer property +alert( String(Math.trunc(Number("1.2"))) ); // "1", not same "1.2" ⇒ not integer property ``` ```` -...Por outro lado, se as chaves (*keys*) forem não-inteiras, elas são listadas segundo a ordem em que foram criadas, por exemplo: +...On the other hand, if the keys are non-integer, then they are listed in the creation order, for instance: ```js run let user = { name: "John", surname: "Smith" }; -user.age = 25; // adicione mais uma propriedade +user.age = 25; // add one more *!* -// propriedades não-inteiras são listadas segundo a ordem em que foram criadas +// non-integer properties are listed in the creation order */!* for (let prop in user) { - alert( prop ); // 'name', 'surname', 'age' + alert( prop ); // name, surname, age } ``` -Portanto, para corrigir o problema dos indicativos telefónicos, podemos "aldrabar" tornando-os não-inteiros. Adicionar um sinal de mais `"+"`, antes de cada código é o suficiente. +So, to fix the issue with the phone codes, we can "cheat" by making the codes non-integer. Adding a plus `"+"` sign before each code is enough. -Desta forma: +Like this: ```js run let codes = { - "+49": "Alemanha", - "+41": "Suiça", - "+44": "Grã Bretanha", + "+49": "Germany", + "+41": "Switzerland", + "+44": "Great Britain", // .., - "+1": "EUA" + "+1": "USA" }; for (let code in codes) { @@ -457,30 +461,30 @@ for (let code in codes) { } ``` -Agora, funciona como pretendido. +Now it works as intended. -## Cópia por referência +## Copying by reference -Uma das principais diferenças entre objetos vs primitivos, está em que os primeiros são armazenados e copiados "por referência" (*by reference*). +One of the fundamental differences of objects vs primitives is that they are stored and copied "by reference". -Valores primitivos: *strings*, números, booleanos -- são atribuidos/copiados como "o próprio valor". +Primitive values: strings, numbers, booleans -- are assigned/copied "as a whole value". -Por exemplo: +For instance: ```js let message = "Hello!"; let phrase = message; ``` -Como resultado, temos duas variáveis independentes, mas cada uma armazenando a *string* (cadeia-de-carateres) `"Hello!"`. +As a result we have two independent variables, each one is storing the string `"Hello!"`. ![](variable-copy-value.svg) -Objetos não são assim. +Objects are not like that. -**Uma variável não armazena o próprio objeto, mas o seu "endereço em memória" (*address in memory*), por outras palavras "uma referência" (*reference*) a ele.** +**A variable stores not the object itself, but its "address in memory", in other words "a reference" to it.** -Aqui, está a imagem para o objeto: +Here's the picture for the object: ```js let user = { @@ -490,25 +494,25 @@ let user = { ![](variable-contains-reference.svg) -Aqui, o objeto é armazenado algures na memória. E a variável `user` contém uma "referência" para ele. +Here, the object is stored somewhere in memory. And the variable `user` has a "reference" to it. -**Quando uma variável com um objeto é copiada -- é a referência copiada, o objeto não é duplicado.** +**When an object variable is copied -- the reference is copied, the object is not duplicated.** -Se imaginarmos um objeto como um fichário, então uma variável será uma chave (*a key*) para ele. Copiando uma variável duplica a chave (*the key*), não o próprio fichário. +If we imagine an object as a cabinet, then a variable is a key to it. Copying a variable duplicates the key, but not the cabinet itself. -Por exemplo: +For instance: ```js no-beautify let user = { name: "John" }; -let admin = user; // copia a referência +let admin = user; // copy the reference ``` -Agora, temos duas variáveis, e cada uma com a referência para o mesmo objeto: +Now we have two variables, each one with the reference to the same object: ![](variable-copy-reference.svg) -Podemos utilizar qualquer das variáveis, para aceder ao fichário e alterar o seu conteúdo: +We can use any variable to access the cabinet and modify its contents: ```js run let user = { name: 'John' }; @@ -516,46 +520,46 @@ let user = { name: 'John' }; let admin = user; *!* -admin.name = 'Pete'; // alterado através da referência em "admin" +admin.name = 'Pete'; // changed by the "admin" reference */!* -alert(*!*user.name*/!*); // 'Pete', as alterações também são visíveis por meio da referência em "user" +alert(*!*user.name*/!*); // 'Pete', changes are seen from the "user" reference ``` -O exemplo acima, demonstra que apenas existe um objecto. Como se tivéssemos um fichário com duas chaves, e usássemos uma delas (`admin`) para o aceder. E depois, se mais tarde usássemos a outra chave (`user`) poderíamos ver as alterações. +The example above demonstrates that there is only one object. As if we had a cabinet with two keys and used one of them (`admin`) to get into it. Then, if we later use the other key (`user`) we would see changes. -### Comparação por referência +### Comparison by reference -Os operadores de igualdade `==` e de igualdade exata (*strict*) `===` para objetos funcionam exatamente da mesma forma. +The equality `==` and strict equality `===` operators for objects work exactly the same. -**Dois objetos apenas são iguais se eles forem o mesmo objeto.** +**Two objects are equal only if they are the same object.** -Por exemplo, duas variáveis referenciam o mesmo objeto, elas são iguais: +For instance, two variables reference the same object, they are equal: ```js run let a = {}; -let b = a; // cópia por referência +let b = a; // copy the reference -alert( a == b ); // true (verdadeiro), ambas as variáveis referenciam o mesmo objeto -alert( a === b ); // true (verdadeiro) +alert( a == b ); // true, both variables reference the same object +alert( a === b ); // true ``` -E aqui, dois objetos independentes não são iguais, muito embora ambos sejam vazios: +And here two independent objects are not equal, even though both are empty: ```js run let a = {}; -let b = {}; // dois objetos independentes +let b = {}; // two independent objects -alert( a == b ); // false (falso) +alert( a == b ); // false ``` -Para comparações como `obj1 > obj2` ou para uma comparação com um primitivo `obj == 5`, objetos são convertidos para primitivos. Estudaremos como funciona a conversão de objetos muito em breve, mas para dizer a verdade, tais comparações são muito raramente necessárias e são geralmente o resultado de um erro de código. +For comparisons like `obj1 > obj2` or for a comparison against a primitive `obj == 5`, objects are converted to primitives. We'll study how object conversions work very soon, but to tell the truth, such comparisons are necessary very rarely and usually are a result of a coding mistake. -### Objeto constante +### Const object -Um objeto declarado com `const` *pode* ser alterado. +An object declared as `const` *can* be changed. -Por exemplo: +For instance: ```js run const user = { @@ -569,9 +573,9 @@ user.age = 25; // (*) alert(user.age); // 25 ``` -Parece que a linha `(*)` irá causar um erro, mas não, não há totalmente qualquer problema. Isso, porque `const` apenas fixa o valor de `user`. Então, aqui `user` armazena uma referência para um mesmo objeto pelo tempo todo. A linha `(*)` vai para *dentro* do objeto, não faz uma re-atribuição a `user`. +It might seem that the line `(*)` would cause an error, but no, there's totally no problem. That's because `const` fixes the value of `user` itself. And here `user` stores the reference to the same object all the time. The line `(*)` goes *inside* the object, it doesn't reassign `user`. -A `const` produzirá um erro se tentarmos colocar em `user` qualquer outra coisa, por exemplo: +The `const` would give an error if we try to set `user` to something else, for instance: ```js run const user = { @@ -579,26 +583,26 @@ const user = { }; *!* -// Erro (não é possível reatribuir a 'user') +// Error (can't reassign user) */!* user = { name: "Pete" }; ``` -...Mas, se quisermos tornar as propriedades do objeto constantes? Então, aí `user.age = 25` produzirá um erro. Isso, também é possível. Iremos cobrir isto no capítulo . +...But what if we want to make constant object properties? So that `user.age = 25` would give an error. That's possible too. We'll cover it in the chapter . -## Clonar e fundir, Object.assign +## Cloning and merging, Object.assign -Portanto, a cópia de uma variável de objeto cria mais uma referência para o mesmo objeto. +So, copying an object variable creates one more reference to the same object. -Mas, se quisermos duplicar um objecto? Criar uma cópia independente, um *clone*? +But what if we need to duplicate an object? Create an independent copy, a clone? -Também se pode fazer, mas é um pouco mais difícil, porque não existe método incorporado (*built-in*) ao JavaScript para isso. Na verdade, isso raramente é necessário. A cópia por referência é a maior parte das vezes boa. +That's also doable, but a little bit more difficult, because there's no built-in method for that in JavaScript. Actually, that's rarely needed. Copying by reference is good most of the time. -Mas, se realmente quisermos isto, aí precisaremos de criar um novo objeto e replicar a estrutura do existente iterando pelas suas propriedades e copiando-as, digamos num nível primitivo. +But if we really want that, then we need to create a new object and replicate the structure of the existing one by iterating over its properties and copying them on the primitive level. -Desta forma: +Like this: ```js run let user = { @@ -607,32 +611,32 @@ let user = { }; *!* -let clone = {}; // o novo objeto vazio +let clone = {}; // the new empty object -// copiemos todas as propriedades de 'user' para aquele +// let's copy all user properties into it for (let key in user) { clone[key] = user[key]; } */!* -// agora,'clone' é um clone completamente independente -clone.name = "Pete"; // altere dados nele +// now clone is a fully independent clone +clone.name = "Pete"; // changed the data in it -alert( user.name ); // contudo, ainda está 'John' no objeto original +alert( user.name ); // still John in the original object ``` -Podemos também empregar o método [Object.assign](mdn:js/Object/assign) para isso. +Also we can use the method [Object.assign](mdn:js/Object/assign) for that. -A sintaxe é: +The syntax is: ```js Object.assign(dest, [src1, src2, src3...]) ``` -- Os argumentos `dest`, e `src1, ..., srcN` (que podem ser tantos quantos necessários) são objetos. -- Ele copia as propriedades de todos os objects `src1, ..., srcN` para `dest`. Por outras palavras, propriedades de todos os objetos, a começar pelo segundo, são copiadas para o primeiro. Depois, ele retorna `dest`. +- Arguments `dest`, and `src1, ..., srcN` (can be as many as needed) are objects. +- It copies the properties of all objects `src1, ..., srcN` into `dest`. In other words, properties of all arguments starting from the 2nd are copied into the 1st. Then it returns `dest`. -Por exemplo, podemos utilizá-lo para fundir vários objetos num só: +For instance, we can use it to merge several objects into one: ```js let user = { name: "John" }; @@ -640,25 +644,25 @@ let permissions1 = { canView: true }; let permissions2 = { canEdit: true }; *!* -// copia todas propriedades de 'permissions1' e 'permissions2' para 'user' +// copies all properties from permissions1 and permissions2 into user Object.assign(user, permissions1, permissions2); */!* -// agora, user = { name: "John", canView: true, canEdit: true } +// now user = { name: "John", canView: true, canEdit: true } ``` -Se, o objeto recetor (`user`) já tiver alguma propriedade com o mesmo nome, ela será substituída (*overwritten*): +If the receiving object (`user`) already has the same named property, it will be overwritten: ```js let user = { name: "John" }; -// substitua ('overwrite') 'nome', e adicione 'isAdmin' +// overwrite name, add isAdmin Object.assign(user, { name: "Pete", isAdmin: true }); -// agora, user = { name: "Pete", isAdmin: true } +// now user = { name: "Pete", isAdmin: true } ``` -Podemos também utilizar `Object.assign` para substituir o ciclo (*loop*) acima para uma clonagem simples: +We also can use `Object.assign` to replace the loop for simple cloning: ```js let user = { @@ -671,12 +675,11 @@ let clone = Object.assign({}, user); */!* ``` -Ele copia todas as propriedades de `user` para o objecto vazio e retorna este. Na verdade, é o mesmo laço (*loop*), mas mais curto. - -Até agora, assumimos que todas as propriedades de `user` são primitivas. Mas, propriedades podem ser referências para outros objetos. O que fazer nesse caso? +It copies all properties of `user` into the empty object and returns it. Actually, the same as the loop, but shorter. -Como aqui: +Until now we assumed that all properties of `user` are primitive. But properties can be references to other objects. What to do with them? +Like this: ```js run let user = { name: "John", @@ -689,10 +692,9 @@ let user = { alert( user.sizes.height ); // 182 ``` -Agora, não é suficiente efetuar a cópia `clone.sizes = user.sizes`, porque `user.sizes` é um objeto, e aí seria copiado por referência. Então, `clone` e `user` iriam partilhar a mesma propriedade "*sizes*": - -Deste modo: +Now it's not enough to copy `clone.sizes = user.sizes`, because the `user.sizes` is an object, it will be copied by reference. So `clone` and `user` will share the same sizes: +Like this: ```js run let user = { name: "John", @@ -704,48 +706,49 @@ let user = { let clone = Object.assign({}, user); -alert( user.sizes === clone.sizes ); // true (verdadeiro), é o mesmo objeto +alert( user.sizes === clone.sizes ); // true, same object -// 'user' e 'clone' partilham 'sizes' -user.sizes.width++; // altere uma propriedade num lugar -alert(clone.sizes.width); // 51, e verá o resultado a partir do outro +// user and clone share sizes +user.sizes.width++; // change a property from one place +alert(clone.sizes.width); // 51, see the result from the other one ``` -Para corrigir isso, deveriamos empregar o laço (*loop*) para clonagem, que examina cada valor de `user[key]` e, se for um objeto, então também replica essa estrutura. Essa, é chamada de uma "clonagem profunda" ("*deep cloning*"). +To fix that, we should use the cloning loop that examines each value of `user[key]` and, if it's an object, then replicate its structure as well. That is called a "deep cloning". + +There's a standard algorithm for deep cloning that handles the case above and more complex cases, called the [Structured cloning algorithm](http://w3c.github.io/html/infrastructure.html#safe-passing-of-structured-data). In order not to reinvent the wheel, we can use a working implementation of it from the JavaScript library [lodash](https://lodash.com), the method is called [_.cloneDeep(obj)](https://lodash.com/docs#cloneDeep). + -Existe um algoritmo padrão (*standard*) para clonagem profunda (deep cloning), que trata tanto do caso acima como de mais complexos, chamado de [Structured cloning algorithm](http://w3c.github.io/html/infrastructure.html#safe-passing-of-structured-data) (algoritmo de clonagem de estruturas). Para não se reinventar a roda, poderemos utilizar uma implementação operacional do mesmo disponível na biblioteca (*library*) de JavaScript [lodash](https://lodash.com), o método é chamado [_.cloneDeep(obj)](https://lodash.com/docs#cloneDeep). -## Sumário +## Summary -Objetos são *arrays* associativos (*associative arrays*), com várias funcionalidades especiais. +Objects are associative arrays with several special features. -Eles armazenam propriedades em pares chave-valor, onde: -- As chaves das propriedades devem ser *strings* ou símbolos (geralmente *strings*). -- Valores podem ser de qualquer tipo. +They store properties (key-value pairs), where: +- Property keys must be strings or symbols (usually strings). +- Values can be of any type. -Para aceder a uma propriedade, podemos utilizar: -- A notação por ponto: `obj.property`. -- A notação por parênteses retos `obj["property"]`. Os parênteses retos permitem receber a chave de uma variável, como por exemplo `obj[varWithKey]`. +To access a property, we can use: +- The dot notation: `obj.property`. +- Square brackets notation `obj["property"]`. Square brackets allow to take the key from a variable, like `obj[varWithKey]`. -Operadores adicionais: -- Para remover uma propriedade: `delete obj.prop`. -- Para verificar se uma propriedade com uma dada chave existe: `"key" in obj`. -- Para iterar sobre um objeto: o ciclo `for (let key in obj)`. +Additional operators: +- To delete a property: `delete obj.prop`. +- To check if a property with the given key exists: `"key" in obj`. +- To iterate over an object: `for (let key in obj)` loop. -Objetos são atribuidos e copiados por referência. Por outras palavras, uma variável não armazena o "valor do objeto", mas uma "referência" (endereço em memória) do valor. Assim, copiar tal variável ou passá-la como argumento de uma função copia tal referência, não o objeto. Todas as operações sobre cópias de referências (como adicionar/remover propriedades) são executadas sobre um mesmo único objeto. +Objects are assigned and copied by reference. In other words, a variable stores not the "object value", but a "reference" (address in memory) for the value. So copying such a variable or passing it as a function argument copies that reference, not the object. All operations via copied references (like adding/removing properties) are performed on the same single object. - Para efetuar uma "verdadeira cópia" (um clone), podemos utilizar `Object.assign` ou [_.cloneDeep(obj)](https://lodash.com/docs#cloneDeep). +To make a "real copy" (a clone) we can use `Object.assign` or [_.cloneDeep(obj)](https://lodash.com/docs#cloneDeep). -O que estudámos neste capítulo é o chamado "objeto simples" ("*plain object*"), ou simplesmente `Objeto`. +What we've studied in this chapter is called a "plain object", or just `Object`. -Existem muitos outros tipos de objetos em JavaScript: +There are many other kinds of objects in JavaScript: -- `Array` para armazenar coleções de dados ordenadas, -- `Date` para armazenar informação sobre data e tempo, -- `Error` para armazenar informação sobre um erro. -- ...E outros mais. +- `Array` to store ordered data collections, +- `Date` to store the information about the date and time, +- `Error` to store the information about an error. +- ...And so on. -Eles têm as suas funcionalidades especiais, que estudaremos mais adiante. Por vezes, pessoas dizem algo como "o tipo -Array" ou "o tipo Data" (*Date*), mas formalmente eles não são própriamente tipos, mas pertencem a um único tipo de dados "objeto". E o extendem de várias formas. +They have their special features that we'll study later. Sometimes people say something like "Array type" or "Date type", but formally they are not types of their own, but belong to a single "object" data type. And they extend it in various ways. -Objetos em JavaScript são muito poderosos. Aqui, apenas tocámos na superfície de um realmente amplo tópico. Iremos, mais especificamente, trabalhar e aprender sobre objetos em futuras partes do tutorial. +Objects in JavaScript are very powerful. Here we've just scratched the surface of a topic that is really huge. We'll be closely working with objects and learning more about them in further parts of the tutorial. diff --git a/1-js/04-object-basics/index.md b/1-js/04-object-basics/index.md index 991117d25..d2387aafa 100644 --- a/1-js/04-object-basics/index.md +++ b/1-js/04-object-basics/index.md @@ -1 +1 @@ -# Objetos: o básico +# Objects: the basics From a9f22831ed1554247971cad1069160b2aa80f688 Mon Sep 17 00:00:00 2001 From: odsantos Date: Fri, 1 Nov 2019 01:05:51 +0100 Subject: [PATCH 3/8] add translation to article --- 1-js/04-object-basics/03-symbol/article.md | 205 ++++++++++----------- 1 file changed, 102 insertions(+), 103 deletions(-) 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. From e8d5265fb476d7e05dae2fd8140da16d47e6e20d Mon Sep 17 00:00:00 2001 From: Osvaldo Dias dos Santos Date: Sun, 20 Sep 2020 22:55:51 +0100 Subject: [PATCH 4/8] Update Symbol article. --- 1-js/04-object-basics/08-symbol/article.md | 118 ++++++++++----------- 1 file changed, 54 insertions(+), 64 deletions(-) diff --git a/1-js/04-object-basics/08-symbol/article.md b/1-js/04-object-basics/08-symbol/article.md index 222cd6ba2..60e7fb082 100644 --- a/1-js/04-object-basics/08-symbol/article.md +++ b/1-js/04-object-basics/08-symbol/article.md @@ -3,11 +3,11 @@ 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. -Até agora, vimos apenas utilizando *strings*. Então, vejamos os benefícios que *symbols* nos dão. +Até agora, vimos apenas utilizando *strings*. Então, vejamos os benefícios que *symbols* nos podem dar. ## Símbolos -Um "símbolo" representa um único identicador. +Um "símbolo" representa um único identificador. Um valor deste tipo, pode ser criado utilizando `Symbol()`: @@ -16,14 +16,14 @@ Um valor deste tipo, pode ser criado utilizando `Symbol()`: let id = Symbol(); ``` -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): +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): ```js run // 'id' é um símbolo com a descrição "id" let id = Symbol("id"); ``` -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. +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. Por exemplo, aqui estão dois símbolos com a mesma descrição -- eles não são iguais: @@ -36,24 +36,25 @@ alert(id1 == id2); // false (falso) */!* ``` -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. +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. ````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. +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. -Por exemplo, este `alert` exibirá um erro: +Por exemplo, este `alert` irá mostrar 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' + // (TypeError: Não é possível converter um valor 'Symbol' para uma 'string') */!* ``` -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. +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. + +Se realmente quisermos mostrar um *symbol*, teremos que explicitamente invocar `.toString()` sobre ele, como aqui: -Se realmente quisermos exibir um *symbol*, temos que explicitamente invocar `.toString()` sobre ele, como aqui: ```js run let id = Symbol("id"); *!* @@ -61,7 +62,8 @@ alert(id.toString()); // 'Symbol(id)', agora funciona */!* ``` -Ou empregar a propriedade `symbol.description` para apenas mostrar a sua descrição: +Ou usar a propriedade `symbol.description` para mostrar apenas a sua descrição: + ```js run let id = Symbol("id"); *!* @@ -73,9 +75,9 @@ alert(id.description); // 'id' ## Propriedades "Ocultas" -Símbolos permitem-nos criar propriedades "ocultas" para um objeto, que nenhuma outra parte do código as possa aceder ou alterar. +Símbolos nos permitem criar propriedades "ocultas" num objeto, que nenhuma outra parte do código possa acidentalmente aceder ou alterar. -Por exemplo, se estivermos a trabalhar com objetos `user`, que pertençam a código de terceiros. E queremos de adicionar identicadores a eles. +Por exemplo, se estivermos a trabalhar com um objeto `user`, que pertence a um código de terceiros, e quisermos adicionar identificadores a ele. Vamos utilizar uma chave *symbol* para isso: @@ -93,9 +95,9 @@ alert( user[id] ); // podemos aceder aos dados usando o 'symbol' como chave (key Qual o benefício de se usar `Symbol("id")` sobre uma *string* `"id"`? -Façamos um exemplo um pouco mais aprofundado para o vermos. +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. -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. +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. Então, aquele programa pode criar o seu próprio `Symbol("id")`, desta forma: @@ -103,12 +105,12 @@ Então, aquele programa pode criar o seu próprio `Symbol("id")`, desta forma: // ... let id = Symbol("id"); -user[id] = "O seu 'id' é válido"; +user[id] = "O valor 'id' do outro programa"; ``` -Não haverá conflito, porque símbolos são sempre diferentes, mesmo que tenham o mesmo nome. +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. -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: +...Mas, se tivéssemos usado uma *string* `"id"` em vez de um *symbol* para o mesmo propósito, então *haveria* um conflito: ```js run let user = { name: "John" }; @@ -118,13 +120,13 @@ user.id = "O nosso valor 'id'"; // ...Um outro script também quer "id" para os seus fins... -user.id = "O seu valor 'id'" +user.id = "O valor 'id' dos outros" // Boom! Alterado pelo outro script! ``` -### Símbolos num literal +### Símbolos num objeto literal -Se quisermos utilizar um *symbol* num objeto literal, precisamos de parênteses retos. +Se quisermos utilizar um *symbol* num objeto literal `{...}`, precisamos de parênteses retos. Desta forma: @@ -134,12 +136,12 @@ let id = Symbol("id"); let user = { name: "John", *!* - [id]: 123 // não "id: 123" + [id]: 123 // não "id": 123 */!* }; ``` -Isto, porque precisamos do valor que está na variável `id` como chave (*key*), não da *string* "id". +Isto, porque precisamos do valor que está na variável `id` como chave, não da *string* "id". ### Símbolos são saltados num *for..in* @@ -163,7 +165,7 @@ for (let key in user) alert(key); // 'name', 'age' (nenhum símbolo) alert( "Direct: " + user[id] ); ``` -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. +`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. Em contraste, [Object.assign](mdn:js/Object/assign) copia ambas as propriedades *string* e *symbol*: @@ -178,55 +180,37 @@ let clone = Object.assign({}, user); alert( clone[id] ); // 123 ``` -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="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*. - -Por exemplo, um número `0` torna-se numa *string* `"0"` quando usado como chave de uma propriedade: - -```js run -let obj = { - 0: "test" // o mesmo que "0": "test" -}; - -// ambos os *alerts* acedem à mesma propriedade (o número 0 é convertido para a *string* "0") -alert( obj["0"] ); // test -alert( obj[0] ); // test (a mesma propriedade) -``` -```` +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`). ## Símbolos globais -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"`, significando este uma única mesma propriedade. +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. -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*. +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*. -Para criar e ler um *symbol* do registo, use `Symbol.for(key)`. +Para ler (e criar, se ausente) um *symbol* do registo, use `Symbol.for(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`. +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`. Por exemplo: ```js run // lê a partir do registo global -let id = Symbol.for("id"); // se o símbolo não existir, ele o cria +let id = Symbol.for("id"); // se o símbolo não existir, ele é criado -// volta a ler +// volta a ler (talvez a partir de outra secção no código) let idAgain = Symbol.for("id"); // é o mesmo símbolo alert( id === idAgain ); // true (verdadeiro) ``` -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. +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. ```smart header="Isto parece Ruby" Em algumas linguagens de programação, como Ruby, existe um único *symbol* por nome. -Em JavaScript, como podemos ver, esses são símbolos globais. +Em JavaScript, como podemos ver, esses são os símbolos globais. ``` ### Symbol.keyFor @@ -236,27 +220,34 @@ Para símbolos globais, não apenas `Symbol.for(key)` retorna um *symbol* por no Por exemplo: ```js run +// obtenha o símbolo a partir do nome let sym = Symbol.for("name"); let sym2 = Symbol.for("id"); -// Obtenha o nome do 'symbol' +// obtenha o nome a partir do 'symbol' alert( Symbol.keyFor(sym) ); // 'name' alert( Symbol.keyFor(sym2) ); // 'id' ``` 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`. +Deste modo, todos os símbolos têm uma propriedade `description`. + Por exemplo: ```js run -alert( Symbol.keyFor(Symbol.for("name")) ); // 'name', símbolo global +let globalSymbol = Symbol.for("name"); +let localSymbol = Symbol("name"); + +alert( Symbol.keyFor(globalSymbol) ); // 'name', símbolo global +alert( Symbol.keyFor(localSymbol) ); // 'undefined', não global -alert( Symbol.keyFor(Symbol("name2")) ); // undefined, o argumento não é um símbolo global +alert( localSymbol.description ); // 'name' ``` ## Símbolos do sistema -Existem muitos símbolos do "sistema" que o JavaScript usa internamente, e os podemos utilizar para afinar vários aspetos dos nossos objetos. +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. Eles vêm listados na especificação, na tabela [Well-known symbols](https://tc39.github.io/ecma262/#sec-well-known-symbols): @@ -266,26 +257,25 @@ Eles vêm listados na especificação, na tabela [Well-known symbols](https://tc - `Symbol.toPrimitive` - ... e assim por diante. -Por exemplo, `Symbol.toPrimitive` permite-nos descrever a conversão objeto-para-primitivo. Veremos o seu uso muito em breve. +Por exemplo, `Symbol.toPrimitive` nos permite descrever a conversão objeto-para-primitivo. Veremos o seu uso muito em breve. Outros *symbols* também se tornarão familiares quando estudarmos as funcionalidades correspondentes na linguagem. -## Sumário +## Resumo -`Symbol`, é um tipo primitivo para identicadores únicos. +`Symbol`, é um tipo primitivo para identificadores únicos. Símbolos são criados pela chamada a `Symbol()`, com uma descrição opcional. -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. +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. Símbolos têm dois principais casos práticos: 1. "Ocultação" de propriedades de objetos. + 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. - 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 . - - Assim, podemos "secretamente" esconder em objetos algo que precisemos, e que outros não possam ver, empregando propriedades simbólicas. + Assim, podemos "secretamente" esconder nos objetos algo que precisemos, que outros não devam ver, empregando propriedades simbólicas. -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. +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. -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. +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. From bdce133275df80d31d7d7ae150aaa4429172fe1d Mon Sep 17 00:00:00 2001 From: Osvaldo Dias dos Santos Date: Fri, 18 Dec 2020 00:16:58 +0100 Subject: [PATCH 5/8] Update "Symbols" translation. --- 1-js/04-object-basics/08-symbol/article.md | 62 ++++++++++------------ 1 file changed, 29 insertions(+), 33 deletions(-) diff --git a/1-js/04-object-basics/08-symbol/article.md b/1-js/04-object-basics/08-symbol/article.md index 60e7fb082..4d4a153e4 100644 --- a/1-js/04-object-basics/08-symbol/article.md +++ b/1-js/04-object-basics/08-symbol/article.md @@ -1,22 +1,22 @@ # O tipo Symbol -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. +Segundo a especificação, as chaves das propriedades dos objetos podem ser quer do tipo *string* como do tipo *symbol*. Não números, nem booleanos, mas apenas *strings* ou *symbols* (símbolos), estes dois tipos. -Até agora, vimos apenas utilizando *strings*. Então, vejamos os benefícios que *symbols* nos podem dar. +Até agora, apenas utilizámos *strings*. Então, vamos ver os benefícios que *symbols* nos podem dar. ## Símbolos -Um "símbolo" representa um único identificador. +Um "símbolo" representa um identificador único . -Um valor deste tipo, pode ser criado utilizando `Symbol()`: +Um valor deste tipo pode ser criado usando `Symbol()`: ```js // 'id' é um novo símbolo let id = Symbol(); ``` -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): +Quando o criamos, podemos dar ao símbolo uma descrição (também chamada de nome do símbolo), sendo ela mais útil para propósitos de *debugging* (depuração de erros): ```js run // 'id' é um símbolo com a descrição "id" @@ -36,7 +36,7 @@ alert(id1 == id2); // false (falso) */!* ``` -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. +Se você tiver familiaridade com Ruby, ou outra linguagem que também tenha alguma espécie de "símbolos" -- por favor, não se confunda. Os símbolos em JavaScript, são diferentes. ````warn header="Símbolos não são auto-convertidos para strings" 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. @@ -46,15 +46,13 @@ Por exemplo, este `alert` irá mostrar 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') +alert(id); // TypeError: Cannot convert a Symbol value to a string (ErroDeTipo: Não é possível converter um valor 'Symbol' para uma 'string') */!* ``` -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. - -Se realmente quisermos mostrar um *symbol*, teremos que explicitamente invocar `.toString()` sobre ele, como aqui: +Esta é uma "salvaguarda na linguagem" contra tal mistura, porque *strings* e *symbols* são fundamentalmente diferentes, e não deveriam ser acidentalmente convertidos de um tipo para o outro. +Se realmente quisermos exibir um *symbol*, teremos que explicitamente invocar `.toString()` sobre ele, como aqui: ```js run let id = Symbol("id"); *!* @@ -63,7 +61,6 @@ alert(id.toString()); // 'Symbol(id)', agora funciona ``` Ou usar a propriedade `symbol.description` para mostrar apenas a sua descrição: - ```js run let id = Symbol("id"); *!* @@ -77,7 +74,7 @@ alert(id.description); // 'id' Símbolos nos permitem criar propriedades "ocultas" num objeto, que nenhuma outra parte do código possa acidentalmente aceder ou alterar. -Por exemplo, se estivermos a trabalhar com um objeto `user`, que pertence a um código de terceiros, e quisermos adicionar identificadores a ele. +Por exemplo, se estivermos a trabalhar com um objeto `user`, que pertença a um código de terceiros, e quisermos adicionar identificadores a ele. Vamos utilizar uma chave *symbol* para isso: @@ -95,9 +92,9 @@ alert( user[id] ); // podemos aceder aos dados usando o 'symbol' como chave (key Qual o benefício de se usar `Symbol("id")` sobre uma *string* `"id"`? -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. +Como o objeto `user` pertence a outro código, e aquele código funciona 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. -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. +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 estes *scripts* podem não ter nenhum conhecimento um do outro. Então, aquele programa pode criar o seu próprio `Symbol("id")`, desta forma: @@ -105,7 +102,7 @@ Então, aquele programa pode criar o seu próprio `Symbol("id")`, desta forma: // ... let id = Symbol("id"); -user[id] = "O valor 'id' do outro programa"; +user[id] = "O valor 'id' dos outros"; ``` 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. @@ -140,7 +137,6 @@ let user = { */!* }; ``` - Isto, porque precisamos do valor que está na variável `id` como chave, não da *string* "id". ### Símbolos são saltados num *for..in* @@ -165,7 +161,7 @@ for (let key in user) alert(key); // 'name', 'age' (nenhum símbolo) alert( "Direct: " + user[id] ); ``` -`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. +`Object.keys(user)` também os ignora. Isto, faz 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. Em contraste, [Object.assign](mdn:js/Object/assign) copia ambas as propriedades *string* e *symbol*: @@ -180,17 +176,17 @@ let clone = Object.assign({}, user); alert( clone[id] ); // 123 ``` -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`). +Não existe nenhum paradoxo aqui. Assim está concebido. A ideia é que ao clonar um objeto ou fundir (*merge*) objetos, geralmente queremos *todas* as propriedades copiadas (incluindo símbolos como `id`). ## Símbolos globais -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. +Como nós vimos, geralmente todos os *symbols* são diferentes, mesmo que tenham o mesmo nome. Mas, por vezes queremos que *symbols* com o mesmo nome sejam entidades únicas. Por exemplo, diferentes partes da nossa aplicação querem aceder ao *symbol* `"id"`, sendo este exatamente a mesma propriedade. -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*. +Para alcançar isto, existe um *registo global de símbolos* (*global symbol registry*). Nós podemos criar *symbols* nele e os aceder mais tarde, e ele garante que acessos repetidos ao mesmo nome retornem exatamente o mesmo *symbol*. -Para ler (e criar, se ausente) um *symbol* do registo, use `Symbol.for(key)`. +Para ler (criar, se ausente) um *symbol* do registo, use `Symbol.for(key)`. -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`. +Esta 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`. Por exemplo: @@ -205,9 +201,9 @@ let idAgain = Symbol.for("id"); alert( id === idAgain ); // true (verdadeiro) ``` -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. +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 lugar no código -- é para isso que eles servem. -```smart header="Isto parece Ruby" +```smart header="Isso parece Ruby" Em algumas linguagens de programação, como Ruby, existe um único *symbol* por nome. Em JavaScript, como podemos ver, esses são os símbolos globais. @@ -215,7 +211,7 @@ Em JavaScript, como podemos ver, esses são os símbolos globais. ### Symbol.keyFor -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. +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 o nome de um símbolo global. Por exemplo: @@ -257,25 +253,25 @@ Eles vêm listados na especificação, na tabela [Well-known symbols](https://tc - `Symbol.toPrimitive` - ... e assim por diante. -Por exemplo, `Symbol.toPrimitive` nos permite descrever a conversão objeto-para-primitivo. Veremos o seu uso muito em breve. +Por exemplo, `Symbol.toPrimitive` nos permite descrever a conversão objeto-para-primitivo. Iremos ver o seu uso muito em breve. -Outros *symbols* também se tornarão familiares quando estudarmos as funcionalidades correspondentes na linguagem. +Outros *symbols* também se irão tornar familiares quando estudarmos as funcionalidades correspondentes na linguagem. ## Resumo `Symbol`, é um tipo primitivo para identificadores únicos. -Símbolos são criados pela chamada a `Symbol()`, com uma descrição opcional. +Símbolos são criados pela chamada a `Symbol()`, com uma descrição (nome) opcional. 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. Símbolos têm dois principais casos práticos: 1. "Ocultação" de propriedades de objetos. - 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. + 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 ou alteração acidentais. - Assim, podemos "secretamente" esconder nos objetos algo que precisemos, que outros não devam ver, empregando propriedades simbólicas. + Assim, nós podemos "secretamente" esconder nos objetos algo que precisamos, mas que outros não devam ver, empregando propriedades simbólicas. -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. +2. Existem muitos símbolos do sistema usados pelo 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. -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. +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, assim como métodos e construções sintáticas incorporados não usam esses métodos. From afbe486a75454d9526d7a00288da1db0b7f3949c Mon Sep 17 00:00:00 2001 From: Osvaldo Dias dos Santos Date: Fri, 18 Dec 2020 00:25:18 +0100 Subject: [PATCH 6/8] Update article.md --- 1-js/04-object-basics/08-symbol/article.md | 197 +++++++++++---------- 1 file changed, 101 insertions(+), 96 deletions(-) diff --git a/1-js/04-object-basics/08-symbol/article.md b/1-js/04-object-basics/08-symbol/article.md index 17e73ba50..4d4a153e4 100644 --- a/1-js/04-object-basics/08-symbol/article.md +++ b/1-js/04-object-basics/08-symbol/article.md @@ -1,85 +1,85 @@ -# 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, nem booleanos, mas apenas *strings* 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, apenas utilizámos *strings*. Então, vamos ver os benefícios que *symbols* nos podem dar. -## Symbols +## Símbolos -A "symbol" represents a unique identifier. +Um "símbolo" representa um identificador único . -A value of this type can be created using `Symbol()`: +Um valor deste tipo pode ser criado usando `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: +Quando o criamos, podemos dar ao símbolo uma descrição (também chamada de nome do símbolo), sendo ela mais útil para propósitos de *debugging* (depuração de erros): -```js -// id is a symbol with the description "id" +```js run +// '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, não afeta nada. -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 você tiver familiaridade com Ruby, ou outra linguagem que também tenha alguma espécie de "símbolos" -- por favor, não se confunda. Os 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" +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. -For instance, this `alert` will show an error: +Por exemplo, este `alert` irá mostrar um erro: ```js run let id = Symbol("id"); *!* -alert(id); // TypeError: Cannot convert a Symbol value to a string +alert(id); // TypeError: Cannot convert a Symbol value to a string (ErroDeTipo: 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 accidentally convert one into another. +Esta é uma "salvaguarda na linguagem" contra tal mistura, porque *strings* e *symbols* são fundamentalmente diferentes, e não deveriam ser acidentalmente convertidos de um tipo para o outro. -If we really want to show a symbol, we need to explicitly call `.toString()` on it, like here: +Se realmente quisermos exibir um *symbol*, teremos 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 usar a propriedade `symbol.description` para mostrar apenas 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 accidentally access or overwrite. +Símbolos nos permitem criar propriedades "ocultas" num objeto, que nenhuma outra parte do código possa acidentalmente aceder ou alterar. -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 um objeto `user`, que pertença a um código de terceiros, e quisermos adicionar identificadores a ele. -Let's use a symbol key for it: +Vamos utilizar uma chave *symbol* para isso: ```js run -let user = { // belongs to another code +let user = { // pertence a outro código name: "John" }; @@ -87,45 +87,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"`? -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. +Como o objeto `user` pertence a outro código, e aquele código funciona 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. -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. +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 estes *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 valor 'id' dos outros"; ``` -There will be no conflict, because symbols are always different, even if they have the same name. +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. -Now note that if we used a string `"id"` instead of a symbol for the same purpose, then there *would* be a conflict: +...Mas, se tivéssemos usado 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 valor 'id' dos outros" +// Boom! Alterado pelo outro script! ``` -### Symbols in an object literal +### Símbolos num objeto 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"); @@ -133,17 +133,17 @@ 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". +Isto, porque precisamos do valor que está na variável `id` como chave, não da *string* "id". -### Symbols are skipped by for..in +### Símbolos são saltados num *for..in* -Symbolic properties do not participate in `for..in` loop. +Propriedades simbólicas não são consideradas num laço (*loop*) `for..in`. -For instance: +Por exemplo: ```js run let id = Symbol("id"); @@ -154,16 +154,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. +`Object.keys(user)` também os ignora. Isto, faz 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. -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"); @@ -176,97 +176,102 @@ 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`). - -## Global symbols +Não existe nenhum paradoxo aqui. Assim está concebido. A ideia é que ao clonar um objeto ou fundir (*merge*) objetos, geralmente queremos *todas* as propriedades copiadas (incluindo símbolos como `id`). -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. +## Símbolos globais -For instance, different parts of our application want to access symbol `"id"` meaning exactly the same property. +Como nós vimos, geralmente todos os *symbols* são diferentes, mesmo que tenham o mesmo nome. Mas, por vezes queremos que *symbols* com o mesmo nome sejam entidades únicas. Por exemplo, diferentes partes da nossa aplicação querem aceder ao *symbol* `"id"`, sendo este exatamente a 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 isto, existe um *registo global de símbolos* (*global symbol registry*). Nós podemos criar *symbols* nele e os aceder 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 ler (criar, se ausente) 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`. +Esta 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`. -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 é criado -// read it again +// volta a ler (talvez a partir de outra secção no código) 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 queremos um *symbol* para toda a aplicação, acessível em qualquer lugar no código -- é para isso que eles servem. -```smart header="That sounds like Ruby" -In some programming languages, like Ruby, there's a single symbol per name. +```smart header="Isso 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 os 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 o nome de um símbolo global. -For instance: +Por exemplo: ```js run +// obtenha o símbolo a partir do nome 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 a partir 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 returns `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: +Deste modo, todos os símbolos têm uma propriedade `description`. + +Por exemplo: ```js run -alert( Symbol.keyFor(Symbol.for("name")) ); // name, global symbol +let globalSymbol = Symbol.for("name"); +let localSymbol = Symbol("name"); + +alert( Symbol.keyFor(globalSymbol) ); // 'name', símbolo global +alert( Symbol.keyFor(localSymbol) ); // 'undefined', não global -alert( Symbol.keyFor(Symbol("name2")) ); // undefined, the argument isn't a global symbol +alert( localSymbol.description ); // 'name' ``` -## 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 nós 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. -For instance, `Symbol.toPrimitive` allows us to describe object to primitive conversion. We'll see its use very soon. +Por exemplo, `Symbol.toPrimitive` nos permite descrever a conversão objeto-para-primitivo. Iremos ver o seu uso muito em breve. -Other symbols will also become familiar when we study the corresponding language features. +Outros *symbols* também se irão tornar familiares quando estudarmos as funcionalidades correspondentes na linguagem. -## Summary +## Resumo -`Symbol` is a primitive type for unique identifiers. +`Symbol`, é um tipo primitivo para identificadores únicos. -Symbols are created with `Symbol()` call with an optional description. +Símbolos são criados pela chamada a `Symbol()`, com uma descrição (nome) opcional. -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 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. -Symbols have two main use cases: +Símbolos têm dois principais casos práticos: -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 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. +1. "Ocultação" de propriedades de objetos. + 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 ou alteração acidentais. - So we can "covertly" hide something into objects that we need, but others should not see, using symbolic properties. + Assim, nós podemos "secretamente" esconder nos objetos algo que precisamos, mas que outros não devam 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 do sistema usados pelo 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. -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, assim como métodos e construções sintáticas incorporados não usam esses métodos. From d73cab0782aa5a5a5f1b1961e6d62498b5cde5cc Mon Sep 17 00:00:00 2001 From: Osvaldo Dias dos Santos Date: Tue, 27 Dec 2022 20:23:22 +0100 Subject: [PATCH 7/8] Update Symbol type article --- 1-js/04-object-basics/08-symbol/article.md | 208 +++++++++++---------- 1 file changed, 110 insertions(+), 98 deletions(-) diff --git a/1-js/04-object-basics/08-symbol/article.md b/1-js/04-object-basics/08-symbol/article.md index 479249139..10a98af0a 100644 --- a/1-js/04-object-basics/08-symbol/article.md +++ b/1-js/04-object-basics/08-symbol/article.md @@ -1,85 +1,96 @@ -# O tipo Symbol +# Symbol type -Segundo a especificação, as chaves das propriedades dos objetos podem ser quer do tipo *string* como do tipo *symbol*. Não números, nem booleanos, mas apenas *strings* ou *symbols* (símbolos), estes dois tipos. +By specification, only two primitive types may serve as object property keys: -Até agora, apenas utilizámos *strings*. Então, vamos ver os benefícios que *symbols* nos podem dar. +- string type, or +- symbol type. -## Símbolos +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"]`. -Um "símbolo" representa um identificador único . +Until now we've been using only strings. -Um valor deste tipo pode ser criado usando `Symbol()`: +Now let's explore symbols, see what they can do for us. + +## Symbols + +A "symbol" represents a unique identifier. + +A value of this type can be created using `Symbol()`: ```js -// 'id' é um novo símbolo let id = Symbol(); ``` -Quando o criamos, podemos dar ao símbolo uma descrição (também chamada de nome do símbolo), sendo ela mais útil para propósitos de *debugging* (depuração de erros): +Upon creation, we can give symbols a description (also called a symbol name), mostly useful for debugging purposes: -```js run -// 'id' é um símbolo com a descrição "id" +```js +// id is a symbol with the description "id" let id = Symbol("id"); ``` -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. +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. -Por exemplo, aqui estão dois símbolos com a mesma descrição -- eles não são iguais: +For instance, here are two symbols with the same description -- they are not equal: ```js run let id1 = Symbol("id"); let id2 = Symbol("id"); *!* -alert(id1 == id2); // false (falso) +alert(id1 == id2); // false */!* ``` -Se você tiver familiaridade com Ruby, ou outra linguagem que também tenha alguma espécie de "símbolos" -- por favor, não se confunda. Os símbolos em JavaScript, são diferentes. +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. -````warn header="Símbolos não são auto-convertidos para strings" -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. +So, to summarize, a symbol is a "primitive unique value" with an optional description. Let's see where we can use them. -Por exemplo, este `alert` irá mostrar um erro: +````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. + +For instance, this `alert` will show an error: ```js run let id = Symbol("id"); *!* -alert(id); // TypeError: Cannot convert a Symbol value to a string (ErroDeTipo: Não é possível converter um valor 'Symbol' para uma 'string') +alert(id); // TypeError: Cannot convert a Symbol value to a string */!* ``` -Esta é uma "salvaguarda na linguagem" contra tal mistura, porque *strings* e *symbols* são fundamentalmente diferentes, e não deveriam ser acidentalmente convertidos de um tipo para o outro. +That's a "language guard" against messing up, because strings and symbols are fundamentally different and should not accidentally convert one into another. + +If we really want to show a symbol, we need to explicitly call `.toString()` on it, like here: -Se realmente quisermos exibir um *symbol*, teremos que explicitamente invocar `.toString()` sobre ele, como aqui: ```js run let id = Symbol("id"); *!* -alert(id.toString()); // 'Symbol(id)', agora funciona +alert(id.toString()); // Symbol(id), now it works */!* ``` -Ou usar a propriedade `symbol.description` para mostrar apenas a sua descrição: +Or get `symbol.description` property to show the description only: + ```js run let id = Symbol("id"); *!* -alert(id.description); // 'id' +alert(id.description); // id */!* ``` ```` -## Propriedades "Ocultas" +## "Hidden" properties -Símbolos nos permitem criar propriedades "ocultas" num objeto, que nenhuma outra parte do código possa acidentalmente aceder ou alterar. -Por exemplo, se estivermos a trabalhar com um objeto `user`, que pertença a um código de terceiros, e quisermos adicionar identificadores a ele. +Symbols allow us to create "hidden" properties of an object, that no other part of code can accidentally access or overwrite. -Vamos utilizar uma chave *symbol* para isso: +For instance, if we're working with `user` objects, that belong to a third-party code. We'd like to add identifiers to them. + +Let's use a symbol key for it: ```js run -let user = { // pertence a outro código +let user = { // belongs to another code name: "John" }; @@ -87,45 +98,45 @@ let id = Symbol("id"); user[id] = 1; -alert( user[id] ); // podemos aceder aos dados usando o 'symbol' como chave (key) +alert( user[id] ); // we can access the data using the symbol as the key ``` -Qual o benefício de se usar `Symbol("id")` sobre uma *string* `"id"`? +What's the benefit of using `Symbol("id")` over a string `"id"`? -Como o objeto `user` pertence a outro código, e aquele código funciona 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. +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. -De igual modo, imagine ainda que 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 estes *scripts* podem não ter nenhum conhecimento um do outro. +Also, imagine that another script wants to have its own identifier inside `user`, for its own purposes. -Então, aquele programa pode criar o seu próprio `Symbol("id")`, desta forma: +Then that script can create its own `Symbol("id")`, like this: ```js // ... let id = Symbol("id"); -user[id] = "O valor 'id' dos outros"; +user[id] = "Their id value"; ``` -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. +There will be no conflict between our and their identifiers, because symbols are always different, even if they have the same name. -...Mas, se tivéssemos usado uma *string* `"id"` em vez de um *symbol* para o mesmo propósito, então *haveria* um conflito: +...But if we used a string `"id"` instead of a symbol for the same purpose, then there *would* be a conflict: ```js let user = { name: "John" }; -// O nosso script utiliza uma propriedade "id" -user.id = "O nosso valor 'id'"; +// Our script uses "id" property +user.id = "Our id value"; -// ...Um outro script também quer "id" para os seus fins... +// ...Another script also wants "id" for its purposes... -user.id = "O valor 'id' dos outros" -// Boom! Alterado pelo outro script! +user.id = "Their id value" +// Boom! overwritten by another script! ``` -### Símbolos num objeto literal +### Symbols in an object literal -Se quisermos utilizar um *symbol* num objeto literal `{...}`, precisamos de parênteses retos à sua volta. +If we want to use a symbol in an object literal `{...}`, we need square brackets around it. -Desta forma: +Like this: ```js let id = Symbol("id"); @@ -133,17 +144,17 @@ let id = Symbol("id"); let user = { name: "John", *!* - [id]: 123 // não "id": 123 + [id]: 123 // not "id": 123 */!* }; ``` -Isto, porque precisamos do valor que está na variável `id` como chave, não da *string* "id". +That's because we need the value from the variable `id` as the key, not the string "id". -### Símbolos são saltados num *for..in* +### Symbols are skipped by for..in -Propriedades simbólicas não são consideradas num laço (*loop*) `for..in`. +Symbolic properties do not participate in `for..in` loop. -Por exemplo: +For instance: ```js run let id = Symbol("id"); @@ -154,16 +165,16 @@ let user = { }; *!* -for (let key in user) alert(key); // 'name', 'age' (nenhum símbolo) +for (let key in user) alert(key); // name, age (no symbols) */!* -// o acesso direto por meio do símbolo funciona -alert( "Direct: " + user[id] ); +// the direct access by the symbol works +alert( "Direct: " + user[id] ); // Direct: 123 ``` -[Object.keys(user)](https://developer.mozilla.org/pt-BR/docs/Web/JavaScript/Reference/Global_Objects/Object/keys) também os ignora. Isto, faz 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. +[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. -Em contraste, [Object.assign](mdn:js/Object/assign) copia ambas as propriedades *string* e *symbol*: +In contrast, [Object.assign](mdn:js/Object/assign) copies both string and symbol properties: ```js run let id = Symbol("id"); @@ -176,102 +187,103 @@ let clone = Object.assign({}, user); alert( clone[id] ); // 123 ``` -Não existe nenhum paradoxo aqui. Assim está concebido. A ideia é que ao clonar um objeto ou fundir (*merge*) objetos, geralmente queremos *todas* as propriedades copiadas (incluindo símbolos como `id`). +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`). -## Símbolos globais +## Global symbols -Como nós vimos, geralmente todos os *symbols* são diferentes, mesmo que tenham o mesmo nome. Mas, por vezes queremos que *symbols* com o mesmo nome sejam a mesma entidade. Por exemplo, diferentes partes da nossa aplicação querem aceder ao *symbol* `"id"`, sendo este exatamente a mesma propriedade. +As we've seen, usually all symbols are different, even if they have the same name. But sometimes we want same-named symbols to be same entities. For instance, different parts of our application want to access symbol `"id"` meaning exactly the same property. -Para alcançar isto, existe um *registo global de símbolos* (*global symbol registry*). Nós podemos criar *symbols* nele e os aceder mais tarde, e ele garante que acessos repetidos ao mesmo nome retornem exatamente o mesmo *symbol*. +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 ler (criar, se ausente) um *symbol* do registo, use `Symbol.for(key)`. +In order to read (create if absent) a symbol from the registry, use `Symbol.for(key)`. -Esta 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`. +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`. -Por exemplo: +For instance: ```js run -// lê a partir do registo global -let id = Symbol.for("id"); // se o símbolo não existir, ele é criado +// read from the global registry +let id = Symbol.for("id"); // if the symbol did not exist, it is created -// volta a ler (talvez a partir de outra secção no código) +// read it again (maybe from another part of the code) let idAgain = Symbol.for("id"); -// é o mesmo símbolo -alert( id === idAgain ); // true (verdadeiro) +// the same symbol +alert( id === idAgain ); // true ``` -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 lugar no código -- é para isso que eles servem. +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. -```smart header="Isso parece Ruby" -Em algumas linguagens de programação, como Ruby, existe um único *symbol* por nome. +```smart header="That sounds like Ruby" +In some programming languages, like Ruby, there's a single symbol per name. -Em JavaScript, como podemos ver, esses são os símbolos globais. +In JavaScript, as we can see, that's true for global symbols. ``` ### Symbol.keyFor -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 o nome de um símbolo global. +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)`: -Por exemplo: +For instance: ```js run -// obtenha o símbolo a partir do nome +// get symbol by name let sym = Symbol.for("name"); let sym2 = Symbol.for("id"); -// obtenha o nome a partir do 'symbol' -alert( Symbol.keyFor(sym) ); // 'name' -alert( Symbol.keyFor(sym2) ); // 'id' +// get name by symbol +alert( Symbol.keyFor(sym) ); // name +alert( Symbol.keyFor(sym2) ); // id ``` -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`. +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`. -Deste modo, todos os símbolos têm uma propriedade `description`. +That said, all symbols have the `description` property. -Por exemplo: +For instance: ```js run let globalSymbol = Symbol.for("name"); let localSymbol = Symbol("name"); -alert( Symbol.keyFor(globalSymbol) ); // 'name', símbolo global -alert( Symbol.keyFor(localSymbol) ); // 'undefined', não global +alert( Symbol.keyFor(globalSymbol) ); // name, global symbol +alert( Symbol.keyFor(localSymbol) ); // undefined, not global -alert( localSymbol.description ); // 'name' +alert( localSymbol.description ); // name ``` -## Símbolos do sistema +## System symbols -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. +There exist many "system" symbols that JavaScript uses internally, and we can use them to fine-tune various aspects of our objects. -Eles vêm listados na especificação, na tabela [Well-known symbols](https://tc39.github.io/ecma262/#sec-well-known-symbols): +They are listed in the specification in the [Well-known symbols](https://tc39.github.io/ecma262/#sec-well-known-symbols) table: - `Symbol.hasInstance` - `Symbol.isConcatSpreadable` - `Symbol.iterator` - `Symbol.toPrimitive` -- ... e assim por diante. +- ...and so on. + +For instance, `Symbol.toPrimitive` allows us to describe object to primitive conversion. We'll see its use very soon. -Por exemplo, `Symbol.toPrimitive` nos permite descrever a conversão objeto-para-primitivo. Iremos ver o seu uso muito em breve. +Other symbols will also become familiar when we study the corresponding language features. -Outros *symbols* também se irão tornar familiares quando estudarmos as funcionalidades correspondentes na linguagem. +## Summary -## Resumo +`Symbol` is a primitive type for unique identifiers. -`Symbol`, é um tipo primitivo para identificadores únicos. +Symbols are created with `Symbol()` call with an optional description (name). -Símbolos são criados pela chamada a `Symbol()`, com uma descrição (nome) opcional. +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` with the same `key` return exactly the same symbol. -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. +Symbols have two main use cases: -Símbolos têm dois principais casos práticos: +1. "Hidden" object properties. -1. "Ocultação" de propriedades de objetos. - 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 ou alteração acidentais. + 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. - Assim, nós podemos "secretamente" esconder nos objetos algo que precisamos, mas que outros não devam ver, empregando propriedades simbólicas. + So we can "covertly" hide something into objects that we need, but others should not see, using symbolic properties. -2. Existem muitos símbolos do sistema usados pelo 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. +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. -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, assim como métodos e construções sintáticas incorporados não usam esses métodos. +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. From e623e5a1ed6d540f22cef8065cd4566932427ec9 Mon Sep 17 00:00:00 2001 From: Osvaldo Dias dos Santos Date: Tue, 27 Dec 2022 20:45:32 +0100 Subject: [PATCH 8/8] Merge branch 'javascript-tutorial:master' into update-symbol --- .../01-hello-world/2-hello-alert-ext/task.md | 4 +- .../04-variables/1-hello-variables/task.md | 2 +- .../04-variables/2-declare-variables/task.md | 4 +- .../04-variables/3-uppercast-constant/task.md | 2 +- .../05-types/1-string-quotes/task.md | 4 +- .../1-primitive-conversions-questions/task.md | 4 +- .../solution.md | 2 +- 1-js/02-first-steps/08-operators/article.md | 31 +++-- .../5-rewrite-if-question/solution.md | 2 +- .../10-ifelse/5-rewrite-if-question/task.md | 5 +- 1-js/02-first-steps/10-ifelse/article.md | 8 +- .../02-coding-style/1-style-errors/task.md | 2 +- 1-js/03-code-quality/04-ninja-code/article.md | 9 +- .../05-testing-mocha/3-pow-test-wrong/task.md | 2 +- 1-js/03-code-quality/06-polyfills/article.md | 16 +-- .../01-object/2-hello-object/task.md | 2 +- .../01-object/3-is-empty/task.md | 2 +- .../01-object/5-sum-object/task.md | 2 +- .../02-object-copy/article.md | 131 +++++++++++++----- .../1-string-new-property/task.md | 2 +- .../04-throttle/task.md | 12 +- .../09-call-apply-decorators/article.md | 32 ++--- .../01-property-descriptors/article.md | 11 +- .../3-proto-and-this/solution.md | 3 +- .../4-hamster-proto/solution.md | 4 +- .../01-prototype-inheritance/article.md | 6 +- .../native-prototypes-array-tostring.svg | 39 ------ .../native-prototypes-classes.svg | 87 ------------ .../object-prototype-1.svg | 38 ----- .../object-prototype.svg | 30 ---- .../rabbit-animal-object.svg | 48 ------- .../03-native-prototypes/article.md | 12 +- .../window-onbeforeunload.view/index.html | 19 --- 33 files changed, 185 insertions(+), 392 deletions(-) delete mode 100644 1-js/08-prototypes/02-function-prototype/native-prototypes-array-tostring.svg delete mode 100644 1-js/08-prototypes/02-function-prototype/native-prototypes-classes.svg delete mode 100644 1-js/08-prototypes/02-function-prototype/object-prototype-1.svg delete mode 100644 1-js/08-prototypes/02-function-prototype/object-prototype.svg delete mode 100644 1-js/08-prototypes/02-function-prototype/rabbit-animal-object.svg delete mode 100644 2-ui/5-loading/02-script-async-defer/window-onbeforeunload.view/index.html diff --git a/1-js/02-first-steps/01-hello-world/2-hello-alert-ext/task.md b/1-js/02-first-steps/01-hello-world/2-hello-alert-ext/task.md index f5b34ec3a..4df018baa 100644 --- a/1-js/02-first-steps/01-hello-world/2-hello-alert-ext/task.md +++ b/1-js/02-first-steps/01-hello-world/2-hello-alert-ext/task.md @@ -1,4 +1,4 @@ -importância: 5 +importance: 5 --- @@ -6,4 +6,4 @@ importância: 5 Tome a solução da tarefa anterior . Modifique-o extraindo o conteúdo do script para um arquivo externo `alert.js`, residindo na mesma pasta. -Abra a página, verifique se o alerta funciona. \ No newline at end of file +Abra a página, verifique se o alerta funciona. diff --git a/1-js/02-first-steps/04-variables/1-hello-variables/task.md b/1-js/02-first-steps/04-variables/1-hello-variables/task.md index 372599a6d..effbdd90c 100644 --- a/1-js/02-first-steps/04-variables/1-hello-variables/task.md +++ b/1-js/02-first-steps/04-variables/1-hello-variables/task.md @@ -1,4 +1,4 @@ -importância: 2 +importance: 2 --- diff --git a/1-js/02-first-steps/04-variables/2-declare-variables/task.md b/1-js/02-first-steps/04-variables/2-declare-variables/task.md index a0a0d5fd4..3668331c6 100644 --- a/1-js/02-first-steps/04-variables/2-declare-variables/task.md +++ b/1-js/02-first-steps/04-variables/2-declare-variables/task.md @@ -1,8 +1,8 @@ -importância: 3 +importance: 3 --- # Dando o nome certo 1. Criar uma variável com o nome do nosso planeta. Como você nomearia tal variável? -2. Crie uma variável para armazenar o nome de um visitante atual em um site. Como você nomearia essa variável? \ No newline at end of file +2. Crie uma variável para armazenar o nome de um visitante atual em um site. Como você nomearia essa variável? diff --git a/1-js/02-first-steps/04-variables/3-uppercast-constant/task.md b/1-js/02-first-steps/04-variables/3-uppercast-constant/task.md index b9ae40f72..8c1ca833e 100644 --- a/1-js/02-first-steps/04-variables/3-uppercast-constant/task.md +++ b/1-js/02-first-steps/04-variables/3-uppercast-constant/task.md @@ -1,4 +1,4 @@ -importância: 4 +importance: 4 --- diff --git a/1-js/02-first-steps/05-types/1-string-quotes/task.md b/1-js/02-first-steps/05-types/1-string-quotes/task.md index 7cc2f6f04..92aa395cb 100644 --- a/1-js/02-first-steps/05-types/1-string-quotes/task.md +++ b/1-js/02-first-steps/05-types/1-string-quotes/task.md @@ -1,4 +1,4 @@ -importância: 5 +importance: 5 --- @@ -14,4 +14,4 @@ alert( `olá ${1}` ); // ? alert( `olá ${"name"}` ); // ? alert( `olá ${name}` ); // ? -``` \ No newline at end of file +``` diff --git a/1-js/02-first-steps/07-type-conversions/1-primitive-conversions-questions/task.md b/1-js/02-first-steps/07-type-conversions/1-primitive-conversions-questions/task.md index 8525e9f3e..24bf496be 100644 --- a/1-js/02-first-steps/07-type-conversions/1-primitive-conversions-questions/task.md +++ b/1-js/02-first-steps/07-type-conversions/1-primitive-conversions-questions/task.md @@ -1,4 +1,4 @@ -importância: 5 +importance: 5 --- @@ -23,4 +23,4 @@ null + 1 undefined + 1 ``` -Pense bem, escreva e depois compare com a resposta. \ No newline at end of file +Pense bem, escreva e depois compare com a resposta. diff --git a/1-js/02-first-steps/08-operators/3-primitive-conversions-questions/solution.md b/1-js/02-first-steps/08-operators/3-primitive-conversions-questions/solution.md index dfd061cb6..7370b66af 100644 --- a/1-js/02-first-steps/08-operators/3-primitive-conversions-questions/solution.md +++ b/1-js/02-first-steps/08-operators/3-primitive-conversions-questions/solution.md @@ -22,4 +22,4 @@ undefined + 1 = NaN // (6) 4. The subtraction always converts to numbers, so it makes `" -9 "` a number `-9` (ignoring spaces around it). 5. `null` becomes `0` after the numeric conversion. 6. `undefined` becomes `NaN` after the numeric conversion. -7. Space characters, are trimmed off string start and end when a string is converted to a number. Here the whole string consists of space characters, such as `\t`, `\n` and a "regular" space between them. So, similarly to an empty string, it becomes `0`. +7. Space characters are trimmed off string start and end when a string is converted to a number. Here the whole string consists of space characters, such as `\t`, `\n` and a "regular" space between them. So, similarly to an empty string, it becomes `0`. diff --git a/1-js/02-first-steps/08-operators/article.md b/1-js/02-first-steps/08-operators/article.md index c7327ff92..d52c37a17 100644 --- a/1-js/02-first-steps/08-operators/article.md +++ b/1-js/02-first-steps/08-operators/article.md @@ -50,8 +50,9 @@ The result of `a % b` is the [remainder](https://en.wikipedia.org/wiki/Remainder For instance: ```js run -alert( 5 % 2 ); // 1, a remainder of 5 divided by 2 -alert( 8 % 3 ); // 2, a remainder of 8 divided by 3 +alert( 5 % 2 ); // 1, the remainder of 5 divided by 2 +alert( 8 % 3 ); // 2, the remainder of 8 divided by 3 +alert( 8 % 4 ); // 0, the remainder of 8 divided by 4 ``` ### Exponentiation ** @@ -68,7 +69,7 @@ alert( 2 ** 3 ); // 2³ = 8 alert( 2 ** 4 ); // 2⁴ = 16 ``` -Just like in maths, the exponentiation operator is defined for non-integer numbers as well. +Just like in maths, the exponentiation operator is defined for non-integer numbers as well. For example, a square root is an exponentiation by ½: @@ -80,7 +81,7 @@ alert( 8 ** (1/3) ); // 2 (power of 1/3 is the same as a cubic root) ## String concatenation with binary + -Let's meet features of JavaScript operators that are beyond school arithmetics. +Let's meet the features of JavaScript operators that are beyond school arithmetics. Usually, the plus operator `+` sums numbers. @@ -194,18 +195,18 @@ Here's an extract from the [precedence table](https://developer.mozilla.org/en-U | Precedence | Name | Sign | |------------|------|------| | ... | ... | ... | -| 15 | unary plus | `+` | -| 15 | unary negation | `-` | -| 14 | exponentiation | `**` | -| 13 | multiplication | `*` | -| 13 | division | `/` | -| 12 | addition | `+` | -| 12 | subtraction | `-` | +| 14 | unary plus | `+` | +| 14 | unary negation | `-` | +| 13 | exponentiation | `**` | +| 12 | multiplication | `*` | +| 12 | division | `/` | +| 11 | addition | `+` | +| 11 | subtraction | `-` | | ... | ... | ... | | 2 | assignment | `=` | | ... | ... | ... | -As we can see, the "unary plus" has a priority of `15` which is higher than the `12` of "addition" (binary plus). That's why, in the expression `"+apples + +oranges"`, unary pluses work before the addition. +As we can see, the "unary plus" has a priority of `14` which is higher than the `11` of "addition" (binary plus). That's why, in the expression `"+apples + +oranges"`, unary pluses work before the addition. ## Assignment @@ -303,9 +304,9 @@ Such operators have the same precedence as a normal assignment, so they run afte ```js run let n = 2; -n *= 3 + 5; +n *= 3 + 5; // right part evaluated first, same as n *= 8 -alert( n ); // 16 (right part evaluated first, same as n *= 8) +alert( n ); // 16 ``` ## Increment/decrement @@ -437,7 +438,7 @@ The list of operators: - RIGHT SHIFT ( `>>` ) - ZERO-FILL RIGHT SHIFT ( `>>>` ) -These operators are used very rarely, when we need to fiddle with numbers on the very lowest (bitwise) level. We won't need these operators any time soon, as web development has little use of them, but in some special areas, such as cryptography, they are useful. You can read the [Bitwise Operators](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators#Bitwise) chapter on MDN when a need arises. +These operators are used very rarely, when we need to fiddle with numbers on the very lowest (bitwise) level. We won't need these operators any time soon, as web development has little use of them, but in some special areas, such as cryptography, they are useful. You can read the [Bitwise Operators](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators#bitwise_operators) chapter on MDN when a need arises. ## Comma diff --git a/1-js/02-first-steps/10-ifelse/5-rewrite-if-question/solution.md b/1-js/02-first-steps/10-ifelse/5-rewrite-if-question/solution.md index 638ce81f1..ff32354fa 100644 --- a/1-js/02-first-steps/10-ifelse/5-rewrite-if-question/solution.md +++ b/1-js/02-first-steps/10-ifelse/5-rewrite-if-question/solution.md @@ -1,6 +1,6 @@ ```js -result = (a + b < 4) ? 'Below' : 'Over'; +let result = (a + b < 4) ? 'Below' : 'Over'; ``` diff --git a/1-js/02-first-steps/10-ifelse/5-rewrite-if-question/task.md b/1-js/02-first-steps/10-ifelse/5-rewrite-if-question/task.md index 684e239f2..6bdf8453e 100644 --- a/1-js/02-first-steps/10-ifelse/5-rewrite-if-question/task.md +++ b/1-js/02-first-steps/10-ifelse/5-rewrite-if-question/task.md @@ -4,13 +4,14 @@ importance: 5 # Rewrite 'if' into '?' -Rewrite this `if` using the ternary operator `'?'`: +Rewrite this `if` using the conditional operator `'?'`: ```js +let result; + if (a + b < 4) { result = 'Below'; } else { result = 'Over'; } ``` - diff --git a/1-js/02-first-steps/10-ifelse/article.md b/1-js/02-first-steps/10-ifelse/article.md index 51514062f..82e8800b9 100644 --- a/1-js/02-first-steps/10-ifelse/article.md +++ b/1-js/02-first-steps/10-ifelse/article.md @@ -68,7 +68,7 @@ if (cond) { ## The "else" clause -The `if` statement may contain an optional "else" block. It executes when the condition is falsy. +The `if` statement may contain an optional `else` block. It executes when the condition is falsy. For example: ```js run @@ -181,9 +181,9 @@ alert( message ); It may be difficult at first to grasp what's going on. But after a closer look, we can see that it's just an ordinary sequence of tests: 1. The first question mark checks whether `age < 3`. -2. If true -- it returns `'Hi, baby!'`. Otherwise, it continues to the expression after the colon '":"', checking `age < 18`. -3. If that's true -- it returns `'Hello!'`. Otherwise, it continues to the expression after the next colon '":"', checking `age < 100`. -4. If that's true -- it returns `'Greetings!'`. Otherwise, it continues to the expression after the last colon '":"', returning `'What an unusual age!'`. +2. If true -- it returns `'Hi, baby!'`. Otherwise, it continues to the expression after the colon ":", checking `age < 18`. +3. If that's true -- it returns `'Hello!'`. Otherwise, it continues to the expression after the next colon ":", checking `age < 100`. +4. If that's true -- it returns `'Greetings!'`. Otherwise, it continues to the expression after the last colon ":", returning `'What an unusual age!'`. Here's how this looks using `if..else`: diff --git a/1-js/03-code-quality/02-coding-style/1-style-errors/task.md b/1-js/03-code-quality/02-coding-style/1-style-errors/task.md index 7205df744..b005fc85a 100644 --- a/1-js/03-code-quality/02-coding-style/1-style-errors/task.md +++ b/1-js/03-code-quality/02-coding-style/1-style-errors/task.md @@ -1,4 +1,4 @@ -importância: 4 +importance: 4 --- diff --git a/1-js/03-code-quality/04-ninja-code/article.md b/1-js/03-code-quality/04-ninja-code/article.md index 19bb8f452..96fdf4143 100644 --- a/1-js/03-code-quality/04-ninja-code/article.md +++ b/1-js/03-code-quality/04-ninja-code/article.md @@ -137,7 +137,7 @@ Instead, reuse existing names. Just write new values into them. In a function try to use only variables passed as parameters. -That would make it really hard to identify what's exactly in the variable *now*. And also where it comes from. A person with weak intuition would have to analyze the code line-by-line and track the changes through every code branch. +That would make it really hard to identify what's exactly in the variable *now*. And also where it comes from. The purpose is to develop the intuition and memory of a person reading the code. A person with weak intuition would have to analyze the code line-by-line and track the changes through every code branch. **An advanced variant of the approach is to covertly (!) replace the value with something alike in the middle of a loop or a function.** @@ -155,7 +155,7 @@ function ninjaFunction(elem) { A fellow programmer who wants to work with `elem` in the second half of the function will be surprised... Only during the debugging, after examining the code they will find out that they're working with a clone! -Seen in code regularly. Deadly effective even against an experienced ninja. +Seen in code regularly. Deadly effective even against an experienced ninja. ## Underscores for fun @@ -169,8 +169,7 @@ A smart ninja puts underscores at one spot of code and evades them at other plac Let everyone see how magnificent your entities are! Names like `superElement`, `megaFrame` and `niceItem` will definitely enlighten a reader. -Indeed, from one hand, something is written: `super..`, `mega..`, `nice..` But from the other hand -- that brings no details. A reader may decide to look for a hidden meaning and meditate for an hour or two. - +Indeed, from one hand, something is written: `super..`, `mega..`, `nice..` But from the other hand -- that brings no details. A reader may decide to look for a hidden meaning and meditate for an hour or two of their paid working time. ## Overlap outer variables @@ -180,7 +179,7 @@ When in the light, can't see anything in the darkness.
When in the darkness, can see everything in the light. ``` -Use same names for variables inside and outside a function. As simple. No efforts required. +Use same names for variables inside and outside a function. As simple. No efforts to invent new names. ```js let *!*user*/!* = authenticateUser(); diff --git a/1-js/03-code-quality/05-testing-mocha/3-pow-test-wrong/task.md b/1-js/03-code-quality/05-testing-mocha/3-pow-test-wrong/task.md index 579669730..74dd7e843 100644 --- a/1-js/03-code-quality/05-testing-mocha/3-pow-test-wrong/task.md +++ b/1-js/03-code-quality/05-testing-mocha/3-pow-test-wrong/task.md @@ -1,4 +1,4 @@ -importância: 5 +importance: 5 --- diff --git a/1-js/03-code-quality/06-polyfills/article.md b/1-js/03-code-quality/06-polyfills/article.md index 02be20872..7accbafb9 100644 --- a/1-js/03-code-quality/06-polyfills/article.md +++ b/1-js/03-code-quality/06-polyfills/article.md @@ -1,11 +1,11 @@ # Polyfills and transpilers -The JavaScript language steadily evolves. New proposals to the language appear regularly, they are analyzed and, if considered worthy, are appended to the list at and then progress to the [specification](http://www.ecma-international.org/publications/standards/Ecma-262.htm). +The JavaScript language steadily evolves. New proposals to the language appear regularly, they are analyzed and, if considered worthy, are appended to the list at and then progress to the [specification](https://www.ecma-international.org/publications-and-standards/standards/ecma-262/). Teams behind JavaScript engines have their own ideas about what to implement first. They may decide to implement proposals that are in draft and postpone things that are already in the spec, because they are less interesting or just harder to do. -So it's quite common for an engine to implement only the part of the standard. +So it's quite common for an engine to implement only part of the standard. A good page to see the current state of support for language features is (it's big, we have a lot to study yet). @@ -42,7 +42,7 @@ Usually, a developer runs the transpiler on their own computer, and then deploys Speaking of names, [Babel](https://babeljs.io) is one of the most prominent transpilers out there. -Modern project build systems, such as [webpack](http://webpack.github.io/), provide means to run transpiler automatically on every code change, so it's very easy to integrate into development process. +Modern project build systems, such as [webpack](https://webpack.js.org/), provide a means to run a transpiler automatically on every code change, so it's very easy to integrate into the development process. ## Polyfills @@ -69,20 +69,20 @@ if (!Math.trunc) { // if no such function } ``` -JavaScript is a highly dynamic language, scripts may add/modify any functions, even including built-in ones. +JavaScript is a highly dynamic language. Scripts may add/modify any function, even built-in ones. -Two interesting libraries of polyfills are: +Two interesting polyfill libraries are: - [core js](https://github.com/zloirock/core-js) that supports a lot, allows to include only needed features. -- [polyfill.io](http://polyfill.io) service that provides a script with polyfills, depending on the features and user's browser. +- [polyfill.io](https://polyfill.io/) service that provides a script with polyfills, depending on the features and user's browser. ## Summary In this chapter we'd like to motivate you to study modern and even "bleeding-edge" language features, even if they aren't yet well-supported by JavaScript engines. -Just don't forget to use transpiler (if using modern syntax or operators) and polyfills (to add functions that may be missing). And they'll ensure that the code works. +Just don't forget to use a transpiler (if using modern syntax or operators) and polyfills (to add functions that may be missing). They'll ensure that the code works. -For example, later when you're familiar with JavaScript, you can setup a code build system based on [webpack](http://webpack.github.io/) with [babel-loader](https://github.com/babel/babel-loader) plugin. +For example, later when you're familiar with JavaScript, you can setup a code build system based on [webpack](https://webpack.js.org/) with the [babel-loader](https://github.com/babel/babel-loader) plugin. Good resources that show the current state of support for various features: - - for pure JavaScript. diff --git a/1-js/04-object-basics/01-object/2-hello-object/task.md b/1-js/04-object-basics/01-object/2-hello-object/task.md index e726ff833..998b6abc6 100644 --- a/1-js/04-object-basics/01-object/2-hello-object/task.md +++ b/1-js/04-object-basics/01-object/2-hello-object/task.md @@ -1,4 +1,4 @@ -importância: 5 +importance: 5 --- diff --git a/1-js/04-object-basics/01-object/3-is-empty/task.md b/1-js/04-object-basics/01-object/3-is-empty/task.md index b6b03b91d..67ac5a8f8 100644 --- a/1-js/04-object-basics/01-object/3-is-empty/task.md +++ b/1-js/04-object-basics/01-object/3-is-empty/task.md @@ -1,4 +1,4 @@ -importância: 5 +importance: 5 --- diff --git a/1-js/04-object-basics/01-object/5-sum-object/task.md b/1-js/04-object-basics/01-object/5-sum-object/task.md index c855904d5..a686984d6 100644 --- a/1-js/04-object-basics/01-object/5-sum-object/task.md +++ b/1-js/04-object-basics/01-object/5-sum-object/task.md @@ -1,4 +1,4 @@ -importância: 5 +importance: 5 --- diff --git a/1-js/04-object-basics/02-object-copy/article.md b/1-js/04-object-basics/02-object-copy/article.md index b56a8034b..e80f748ab 100644 --- a/1-js/04-object-basics/02-object-copy/article.md +++ b/1-js/04-object-basics/02-object-copy/article.md @@ -37,7 +37,7 @@ And here's how it's actually stored in memory: The object is stored somewhere in memory (at the right of the picture), while the `user` variable (at the left) has a "reference" to it. -We may think of an object variable, such as `user`, as like a sheet of paper with the address of the object on it. +We may think of an object variable, such as `user`, like a sheet of paper with the address of the object on it. When we perform actions with the object, e.g. take a property `user.name`, the JavaScript engine looks at what's at that address and performs the operation on the actual object. @@ -100,15 +100,37 @@ alert( a == b ); // false For comparisons like `obj1 > obj2` or for a comparison against a primitive `obj == 5`, objects are converted to primitives. We'll study how object conversions work very soon, but to tell the truth, such comparisons are needed very rarely -- usually they appear as a result of a programming mistake. +````smart header="Const objects can be modified" +An important side effect of storing objects as references is that an object declared as `const` *can* be modified. + +For instance: + +```js run +const user = { + name: "John" +}; + +*!* +user.name = "Pete"; // (*) +*/!* + +alert(user.name); // Pete +``` + +It might seem that the line `(*)` would cause an error, but it does not. The value of `user` is constant, it must always reference the same object, but properties of that object are free to change. + +In other words, the `const user` gives an error only if we try to set `user=...` as a whole. + +That said, if we really need to make constant object properties, it's also possible, but using totally different methods. We'll mention that in the chapter . +```` + ## Cloning and merging, Object.assign [#cloning-and-merging-object-assign] So, copying an object variable creates one more reference to the same object. -But what if we need to duplicate an object? Create an independent copy, a clone? - -That's also doable, but a little bit more difficult, because there's no built-in method for that in JavaScript. But there is rarely a need -- copying by reference is good most of the time. +But what if we need to duplicate an object? -But if we really want that, then we need to create a new object and replicate the structure of the existing one by iterating over its properties and copying them on the primitive level. +We can create a new object and replicate the structure of the existing one, by iterating over its properties and copying them on the primitive level. Like this: @@ -133,21 +155,22 @@ clone.name = "Pete"; // changed the data in it alert( user.name ); // still John in the original object ``` -Also we can use the method [Object.assign](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign) for that. +We can also use the method [Object.assign](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign). The syntax is: ```js -Object.assign(dest, [src1, src2, src3...]) +Object.assign(dest, ...sources) ``` - The first argument `dest` is a target object. -- Further arguments `src1, ..., srcN` (can be as many as needed) are source objects. -- It copies the properties of all source objects `src1, ..., srcN` into the target `dest`. In other words, properties of all arguments starting from the second are copied into the first object. -- The call returns `dest`. +- Further arguments is a list of source objects. -For instance, we can use it to merge several objects into one: -```js +It copies the properties of all source objects into the target `dest`, and then returns it as the result. + +For example, we have `user` object, let's add a couple of permissions to it: + +```js run let user = { name: "John" }; let permissions1 = { canView: true }; @@ -159,6 +182,9 @@ Object.assign(user, permissions1, permissions2); */!* // now user = { name: "John", canView: true, canEdit: true } +alert(user.name); // John +alert(user.canView); // true +alert(user.canEdit); // true ``` If the copied property name already exists, it gets overwritten: @@ -171,9 +197,9 @@ Object.assign(user, { name: "Pete" }); alert(user.name); // now user = { name: "Pete" } ``` -We also can use `Object.assign` to replace `for..in` loop for simple cloning: +We also can use `Object.assign` to perform a simple object cloning: -```js +```js run let user = { name: "John", age: 30 @@ -182,15 +208,18 @@ let user = { *!* let clone = Object.assign({}, user); */!* + +alert(clone.name); // John +alert(clone.age); // 30 ``` -It copies all properties of `user` into the empty object and returns it. +Here it copies all properties of `user` into the empty object and returns it. There are also other methods of cloning an object, e.g. using the [spread syntax](info:rest-parameters-spread) `clone = {...user}`, covered later in the tutorial. ## Nested cloning -Until now we assumed that all properties of `user` are primitive. But properties can be references to other objects. What to do with them? +Until now we assumed that all properties of `user` are primitive. But properties can be references to other objects. Like this: ```js run @@ -205,9 +234,7 @@ let user = { alert( user.sizes.height ); // 182 ``` -Now it's not enough to copy `clone.sizes = user.sizes`, because the `user.sizes` is an object, it will be copied by reference. So `clone` and `user` will share the same sizes: - -Like this: +Now it's not enough to copy `clone.sizes = user.sizes`, because `user.sizes` is an object, and will be copied by reference, so `clone` and `user` will share the same sizes: ```js run let user = { @@ -223,37 +250,71 @@ let clone = Object.assign({}, user); alert( user.sizes === clone.sizes ); // true, same object // user and clone share sizes -user.sizes.width++; // change a property from one place -alert(clone.sizes.width); // 51, see the result from the other one +user.sizes.width = 60; // change a property from one place +alert(clone.sizes.width); // 60, get the result from the other one ``` -To fix that, we should use a cloning loop that examines each value of `user[key]` and, if it's an object, then replicate its structure as well. That is called a "deep cloning". +To fix that and make `user` and `clone` truly separate objects, we should use a cloning loop that examines each value of `user[key]` and, if it's an object, then replicate its structure as well. That is called a "deep cloning" or "structured cloning". There's [structuredClone](https://developer.mozilla.org/en-US/docs/Web/API/structuredClone) method that implements deep cloning. -We can use recursion to implement it. Or, to not reinvent the wheel, take an existing implementation, for instance [_.cloneDeep(obj)](https://lodash.com/docs#cloneDeep) from the JavaScript library [lodash](https://lodash.com). -````smart header="Const objects can be modified" -An important side effect of storing objects as references is that an object declared as `const` *can* be modified. +### structuredClone -For instance: +The call `structuredClone(object)` clones the `object` with all nested properties. + +Here's how we can use it in our example: ```js run -const user = { - name: "John" +let user = { + name: "John", + sizes: { + height: 182, + width: 50 + } }; *!* -user.name = "Pete"; // (*) +let clone = structuredClone(user); */!* -alert(user.name); // Pete +alert( user.sizes === clone.sizes ); // false, different objects + +// user and clone are totally unrelated now +user.sizes.width = 60; // change a property from one place +alert(clone.sizes.width); // 50, not related ``` -It might seem that the line `(*)` would cause an error, but it does not. The value of `user` is constant, it must always reference the same object, but properties of that object are free to change. +The `structuredClone` method can clone most data types, such as objects, arrays, primitive values. -In other words, the `const user` gives an error only if we try to set `user=...` as a whole. +It also supports circular references, when an object property references the object itself (directly or via a chain or references). -That said, if we really need to make constant object properties, it's also possible, but using totally different methods. We'll mention that in the chapter . -```` +For instance: + +```js run +let user = {}; +// let's create a circular reference: +// user.me references the user itself +user.me = user; + +let clone = structuredClone(user); +alert(clone.me === clone); // true +``` + +As you can see, `clone.me` references the `clone`, not the `user`! So the circular reference was cloned correctly as well. + +Although, there are cases when `structuredClone` fails. + +For instance, when an object has a function property: + +```js run +// error +structuredClone({ + f: function() {} +}); +``` + +Function properties aren't supported. + +To handle such complex cases we may need to use a combination of cloning methods, write custom code or, to not reinvent the wheel, take an existing implementation, for instance [_.cloneDeep(obj)](https://lodash.com/docs#cloneDeep) from the JavaScript library [lodash](https://lodash.com). ## Summary @@ -261,4 +322,4 @@ Objects are assigned and copied by reference. In other words, a variable stores All operations via copied references (like adding/removing properties) are performed on the same single object. -To make a "real copy" (a clone) we can use `Object.assign` for the so-called "shallow copy" (nested objects are copied by reference) or a "deep cloning" function, such as [_.cloneDeep(obj)](https://lodash.com/docs#cloneDeep). +To make a "real copy" (a clone) we can use `Object.assign` for the so-called "shallow copy" (nested objects are copied by reference) or a "deep cloning" function `structuredClone` or use a custom cloning implementation, such as [_.cloneDeep(obj)](https://lodash.com/docs#cloneDeep). diff --git a/1-js/05-data-types/01-primitives-methods/1-string-new-property/task.md b/1-js/05-data-types/01-primitives-methods/1-string-new-property/task.md index e4764be81..d87bf0174 100644 --- a/1-js/05-data-types/01-primitives-methods/1-string-new-property/task.md +++ b/1-js/05-data-types/01-primitives-methods/1-string-new-property/task.md @@ -1,4 +1,4 @@ -importância: 5 +importance: 5 --- diff --git a/1-js/06-advanced-functions/09-call-apply-decorators/04-throttle/task.md b/1-js/06-advanced-functions/09-call-apply-decorators/04-throttle/task.md index 43136dcb5..cbd473196 100644 --- a/1-js/06-advanced-functions/09-call-apply-decorators/04-throttle/task.md +++ b/1-js/06-advanced-functions/09-call-apply-decorators/04-throttle/task.md @@ -8,7 +8,7 @@ Create a "throttling" decorator `throttle(f, ms)` -- that returns a wrapper. When it's called multiple times, it passes the call to `f` at maximum once per `ms` milliseconds. -The difference with debounce is that it's completely different decorator: +Compared to the debounce decorator, the behavior is completely different: - `debounce` runs the function once after the "cooldown" period. Good for processing the final result. - `throttle` runs it not more often than given `ms` time. Good for regular updates that shouldn't be very often. @@ -21,16 +21,16 @@ Let's check the real-life application to better understand that requirement and In a browser we can setup a function to run at every mouse movement and get the pointer location as it moves. During an active mouse usage, this function usually runs very frequently, can be something like 100 times per second (every 10 ms). **We'd like to update some information on the web-page when the pointer moves.** -Updating function `update()` is too heavy to do it on every micro-movement. There is also no sense in making it more often than once per 100ms. +...But updating function `update()` is too heavy to do it on every micro-movement. There is also no sense in updating more often than once per 100ms. -So we'll assign `throttle(update, 100)` as the function to run on each mouse move instead of the original `update()`. The decorator will be called often, but `update()` will be called at maximum once per 100ms. +So we'll wrap it into the decorator: use `throttle(update, 100)` as the function to run on each mouse move instead of the original `update()`. The decorator will be called often, but forward the call to `update()` at maximum once per 100ms. Visually, it will look like this: -1. For the first mouse movement the decorated variant passes the call to `update`. That's important, the user sees our reaction to their move immediately. +1. For the first mouse movement the decorated variant immediately passes the call to `update`. That's important, the user sees our reaction to their move immediately. 2. Then as the mouse moves on, until `100ms` nothing happens. The decorated variant ignores calls. -3. At the end of `100ms` -- one more `update` happens with the last coordinates. -4. Then, finally, the mouse stops somewhere. The decorated variant waits until `100ms` expire and then runs `update` with last coordinates. So, perhaps the most important, the final mouse coordinates are processed. +3. At the end of `100ms` -- one more `update` happens with the last coordinates. +4. Then, finally, the mouse stops somewhere. The decorated variant waits until `100ms` expire and then runs `update` with last coordinates. So, quite important, the final mouse coordinates are processed. A code example: diff --git a/1-js/06-advanced-functions/09-call-apply-decorators/article.md b/1-js/06-advanced-functions/09-call-apply-decorators/article.md index 12f4e654b..c5d785493 100644 --- a/1-js/06-advanced-functions/09-call-apply-decorators/article.md +++ b/1-js/06-advanced-functions/09-call-apply-decorators/article.md @@ -6,9 +6,9 @@ JavaScript gives exceptional flexibility when dealing with functions. They can b Let's say we have a function `slow(x)` which is CPU-heavy, but its results are stable. In other words, for the same `x` it always returns the same result. -If the function is called often, we may want to cache (remember) the results for different `x` to avoid spending extra-time on recalculations. +If the function is called often, we may want to cache (remember) the results to avoid spending extra-time on recalculations. -But instead of adding that functionality into `slow()` we'll create a wrapper. As we'll see, there are many benefits of doing so. +But instead of adding that functionality into `slow()` we'll create a wrapper function, that adds caching. As we'll see, there are many benefits of doing so. Here's the code, and explanations follow: @@ -23,13 +23,13 @@ function cachingDecorator(func) { let cache = new Map(); return function(x) { - if (cache.has(x)) { // if the result is in the map - return cache.get(x); // return it + if (cache.has(x)) { // if there's such key in cache + return cache.get(x); // read the result from it } - let result = func(x); // otherwise call func + let result = func(x); // otherwise call func - cache.set(x, result); // and cache (remember) the result + cache.set(x, result); // and cache (remember) the result return result; }; } @@ -49,13 +49,11 @@ The idea is that we can call `cachingDecorator` for any function, and it will re By separating caching from the main function code we also keep the main code simpler. -Now let's get into details of how it works. - The result of `cachingDecorator(func)` is a "wrapper": `function(x)` that "wraps" the call of `func(x)` into caching logic: ![](decorator-makecaching-wrapper.svg) -As we can see, the wrapper returns the result of `func(x)` "as is". From an outside code, the wrapped `slow` function still does the same. It just got a caching aspect added to its behavior. +From an outside code, the wrapped `slow` function still does the same. It just got a caching aspect added to its behavior. To summarize, there are several benefits of using a separate `cachingDecorator` instead of altering the code of `slow` itself: @@ -228,9 +226,7 @@ let worker = { worker.slow = cachingDecorator(worker.slow); ``` -We have two tasks to solve here. - -First is how to use both arguments `min` and `max` for the key in `cache` map. Previously, for a single argument `x` we could just `cache.set(x, result)` to save the result and `cache.get(x)` to retrieve it. But now we need to remember the result for a *combination of arguments* `(min,max)`. The native `Map` takes single value only as the key. +Previously, for a single argument `x` we could just `cache.set(x, result)` to save the result and `cache.get(x)` to retrieve it. But now we need to remember the result for a *combination of arguments* `(min,max)`. The native `Map` takes single value only as the key. There are many solutions possible: @@ -238,12 +234,11 @@ There are many solutions possible: 2. Use nested maps: `cache.set(min)` will be a `Map` that stores the pair `(max, result)`. So we can get `result` as `cache.get(min).get(max)`. 3. Join two values into one. In our particular case we can just use a string `"min,max"` as the `Map` key. For flexibility, we can allow to provide a *hashing function* for the decorator, that knows how to make one value from many. - For many practical applications, the 3rd variant is good enough, so we'll stick to it. Also we need to pass not just `x`, but all arguments in `func.call`. Let's recall that in a `function()` we can get a pseudo-array of its arguments as `arguments`, so `func.call(this, x)` should be replaced with `func.call(this, ...arguments)`. -Now let's bake it all into the more powerful `cachingDecorator`: +Here's a more powerful `cachingDecorator`: ```js run let worker = { @@ -264,7 +259,7 @@ function cachingDecorator(func, hash) { } *!* - let result = func.apply(this, arguments); // (**) + let result = func.call(this, ...arguments); // (**) */!* cache.set(key, result); @@ -287,7 +282,7 @@ Now it works with any number of arguments (though the hash function would also n There are two changes: - In the line `(*)` it calls `hash` to create a single key from `arguments`. Here we use a simple "joining" function that turns arguments `(3, 5)` into the key `"3,5"`. More complex cases may require other hashing functions. -- Then `(**)` uses `func.apply` to pass both the context and all arguments the wrapper got (no matter how many) to the original function. +- Then `(**)` uses `func.call(this, ...arguments)` to pass both the context and all arguments the wrapper got (not just the first one) to the original function. ## func.apply @@ -423,10 +418,9 @@ The generic *call forwarding* is usually done with `apply`: ```js let wrapper = function() { return original.apply(this, arguments); -} +}; ``` -We also saw an example of *method borrowing* when we take a method from an object and `call` it in the context of another object. It is quite common to take array methods and apply them to arguments. The alternative is to use rest parameters object that is a real array. - +We also saw an example of *method borrowing* when we take a method from an object and `call` it in the context of another object. It is quite common to take array methods and apply them to `arguments`. The alternative is to use rest parameters object that is a real array. There are many decorators there in the wild. Check how well you got them by solving the tasks of this chapter. diff --git a/1-js/07-object-properties/01-property-descriptors/article.md b/1-js/07-object-properties/01-property-descriptors/article.md index 75df2fefc..0a945b377 100644 --- a/1-js/07-object-properties/01-property-descriptors/article.md +++ b/1-js/07-object-properties/01-property-descriptors/article.md @@ -63,7 +63,7 @@ Object.defineProperty(obj, propertyName, descriptor) ``` `obj`, `propertyName` -: The object and property to work on. +: The object and its property to apply the descriptor. `descriptor` : Property descriptor object to apply. @@ -116,14 +116,14 @@ Object.defineProperty(user, "name", { }); *!* -user.name = "Pete"; // Error: Cannot assign to read only property 'name'... +user.name = "Pete"; // Error: Cannot assign to read only property 'name' */!* ``` Now no one can change the name of our user, unless they apply their own `defineProperty` to override ours. ```smart header="Errors appear only in strict mode" -In the non-strict mode, no errors occur when writing to non-writable properties and such. But the operation still won't succeed. Flag-violating actions are just silently ignored in non-strict. +In non-strict mode, no errors occur when writing to non-writable properties and such. But the operation still won't succeed. Flag-violating actions are just silently ignored in non-strict. ``` Here's the same example, but the property is created from scratch: @@ -140,11 +140,10 @@ Object.defineProperty(user, "name", { */!* }); -alert(user.name); // Pete -user.name = "Alice"; // Error +alert(user.name); // John +user.name = "Pete"; // Error ``` - ## Non-enumerable Now let's add a custom `toString` to `user`. diff --git a/1-js/08-prototypes/01-prototype-inheritance/3-proto-and-this/solution.md b/1-js/08-prototypes/01-prototype-inheritance/3-proto-and-this/solution.md index c7d147b9c..4d6ea2653 100644 --- a/1-js/08-prototypes/01-prototype-inheritance/3-proto-and-this/solution.md +++ b/1-js/08-prototypes/01-prototype-inheritance/3-proto-and-this/solution.md @@ -3,4 +3,5 @@ That's because `this` is an object before the dot, so `rabbit.eat()` modifies `rabbit`. Property lookup and execution are two different things. -The method `rabbit.eat` is first found in the prototype, then executed with `this=rabbit` + +The method `rabbit.eat` is first found in the prototype, then executed with `this=rabbit`. diff --git a/1-js/08-prototypes/01-prototype-inheritance/4-hamster-proto/solution.md b/1-js/08-prototypes/01-prototype-inheritance/4-hamster-proto/solution.md index ca833058e..c141b2ecd 100644 --- a/1-js/08-prototypes/01-prototype-inheritance/4-hamster-proto/solution.md +++ b/1-js/08-prototypes/01-prototype-inheritance/4-hamster-proto/solution.md @@ -10,7 +10,7 @@ Let's look carefully at what's going on in the call `speedy.eat("apple")`. So all hamsters share a single stomach! -Every time the `stomach` is taken from the prototype, then `stomach.push` modifies it "at place". +Both for `lazy.stomach.push(...)` and `speedy.stomach.push()`, the property `stomach` is found in the prototype (as it's not in the object itself), then the new data is pushed into it. Please note that such thing doesn't happen in case of a simple assignment `this.stomach=`: @@ -77,4 +77,4 @@ alert( speedy.stomach ); // apple alert( lazy.stomach ); // ``` -As a common solution, all properties that describe the state of a particular object, like `stomach` above, are usually written into that object. That prevents such problems. +As a common solution, all properties that describe the state of a particular object, like `stomach` above, should be written into that object. That prevents such problems. diff --git a/1-js/08-prototypes/01-prototype-inheritance/article.md b/1-js/08-prototypes/01-prototype-inheritance/article.md index 01703212d..ef6c7ffeb 100644 --- a/1-js/08-prototypes/01-prototype-inheritance/article.md +++ b/1-js/08-prototypes/01-prototype-inheritance/article.md @@ -93,7 +93,6 @@ The method is automatically taken from the prototype, like this: The prototype chain can be longer: - ```js run let animal = { eats: true, @@ -128,11 +127,10 @@ Now if we read something from `longEar`, and it's missing, JavaScript will look There are only two limitations: 1. The references can't go in circles. JavaScript will throw an error if we try to assign `__proto__` in a circle. -2. The value of `__proto__` can be either an object or `null`, other types (like primitives) are ignored. +2. The value of `__proto__` can be either an object or `null`. Other types are ignored. Also it may be obvious, but still: there can be only one `[[Prototype]]`. An object may not inherit from two others. - ```smart header="`__proto__` is a historical getter/setter for `[[Prototype]]`" It's a common mistake of novice developers not to know the difference between these two. @@ -178,7 +176,7 @@ From now on, `rabbit.walk()` call finds the method immediately in the object and ![](proto-animal-rabbit-walk-2.svg) -That's for data properties only, not for accessors. If a property is a getter/setter, then it behaves like a function: getters/setters are looked up in the prototype. +Accessor properties are an exception, as assignment is handled by a setter function. So writing to such a property is actually the same as calling a function. For that reason `admin.fullName` works correctly in the code below: diff --git a/1-js/08-prototypes/02-function-prototype/native-prototypes-array-tostring.svg b/1-js/08-prototypes/02-function-prototype/native-prototypes-array-tostring.svg deleted file mode 100644 index 37601da27..000000000 --- a/1-js/08-prototypes/02-function-prototype/native-prototypes-array-tostring.svg +++ /dev/null @@ -1,39 +0,0 @@ - - - - native-prototypes-array-tostring.svg - Created with sketchtool. - - - - - toString: function - - ... - - - Array.prototype - - - - toString: function - ... - - - Object.prototype - - - - - [[Prototype]] - - - - [[Prototype]] - - - [1, 2, 3] - - - - \ No newline at end of file diff --git a/1-js/08-prototypes/02-function-prototype/native-prototypes-classes.svg b/1-js/08-prototypes/02-function-prototype/native-prototypes-classes.svg deleted file mode 100644 index a6f78e574..000000000 --- a/1-js/08-prototypes/02-function-prototype/native-prototypes-classes.svg +++ /dev/null @@ -1,87 +0,0 @@ - - - - native-prototypes-classes.svg - Created with sketchtool. - - - - - toString: function - other object methods - - - Object.prototype - - - - - null - - - - slice: function - other array methods - - - [[Prototype]] - - - [[Prototype]] - - - [[Prototype]] - - - [[Prototype]] - - - [[Prototype]] - - - [[Prototype]] - - - [[Prototype]] - - - Array.prototype - - - - call: function - other function methods - - - Function.prototype - - - - toFixed: function - other number methods - - - Number.prototype - - - - - - [1, 2, 3] - - - - function f(args) { - ... - } - - - - 5 - - - - - - - \ No newline at end of file diff --git a/1-js/08-prototypes/02-function-prototype/object-prototype-1.svg b/1-js/08-prototypes/02-function-prototype/object-prototype-1.svg deleted file mode 100644 index 8a93d2a86..000000000 --- a/1-js/08-prototypes/02-function-prototype/object-prototype-1.svg +++ /dev/null @@ -1,38 +0,0 @@ - - - - object-prototype-1.svg - Created with sketchtool. - - - - - constructor: Object - toString: function - ... - - - - Object.prototype - - - - Object - - - obj = new Object() - - - - - [[Prototype]] - - - prototype - - - constructor - - - - \ No newline at end of file diff --git a/1-js/08-prototypes/02-function-prototype/object-prototype.svg b/1-js/08-prototypes/02-function-prototype/object-prototype.svg deleted file mode 100644 index 828f61d3b..000000000 --- a/1-js/08-prototypes/02-function-prototype/object-prototype.svg +++ /dev/null @@ -1,30 +0,0 @@ - - - - object-prototype.svg - Created with sketchtool. - - - - - constructor: Object - toString: function - ... - - - Object.prototype - - - - Object - - - - prototype - - - constructor - - - - \ No newline at end of file diff --git a/1-js/08-prototypes/02-function-prototype/rabbit-animal-object.svg b/1-js/08-prototypes/02-function-prototype/rabbit-animal-object.svg deleted file mode 100644 index 28daef3af..000000000 --- a/1-js/08-prototypes/02-function-prototype/rabbit-animal-object.svg +++ /dev/null @@ -1,48 +0,0 @@ - - - - rabbit-animal-object.svg - Created with sketchtool. - - - - - toString: function - hasOwnProperty: function - ... - - - Object.prototype - - - - animal - - - - [[Prototype]] - - - [[Prototype]] - - - - [[Prototype]] - - - null - - - eats: true - - - - rabbit - - - - jumps: true - - - - \ No newline at end of file diff --git a/1-js/08-prototypes/03-native-prototypes/article.md b/1-js/08-prototypes/03-native-prototypes/article.md index 9cf9897b2..bdfc86dd8 100644 --- a/1-js/08-prototypes/03-native-prototypes/article.md +++ b/1-js/08-prototypes/03-native-prototypes/article.md @@ -2,7 +2,7 @@ The `"prototype"` property is widely used by the core of JavaScript itself. All built-in constructor functions use it. -We'll see how it is for plain objects first, and then for more complex ones. +First we'll look at the details, and then how to use it for adding new capabilities to built-in objects. ## Object.prototype @@ -38,7 +38,7 @@ alert(obj.toString === obj.__proto__.toString); //true alert(obj.toString === Object.prototype.toString); //true ``` -Please note that there is no additional `[[Prototype]]` in the chain above `Object.prototype`: +Please note that there is no more `[[Prototype]]` in the chain above `Object.prototype`: ```js run alert(Object.prototype.__proto__); // null @@ -48,9 +48,9 @@ alert(Object.prototype.__proto__); // null Other built-in objects such as `Array`, `Date`, `Function` and others also keep methods in prototypes. -For instance, when we create an array `[1, 2, 3]`, the default `new Array()` constructor is used internally. So the array data is written into the new object, and `Array.prototype` becomes its prototype and provides methods. That's very memory-efficient. +For instance, when we create an array `[1, 2, 3]`, the default `new Array()` constructor is used internally. So `Array.prototype` becomes its prototype and provides methods. That's very memory-efficient. -By specification, all of the built-in prototypes have `Object.prototype` on the top. Sometimes people say that "everything inherits from objects". +By specification, all of the built-in prototypes have `Object.prototype` on the top. That's why some people say that "everything inherits from objects". Here's the overall picture (for 3 built-ins to fit): @@ -124,7 +124,7 @@ String.prototype.show = function() { During the process of development, we may have ideas for new built-in methods we'd like to have, and we may be tempted to add them to native prototypes. But that is generally a bad idea. ```warn -Prototypes are global, so it's easy to get a conflict. If two libraries add a method `String.prototype.show`, then one of them will be overwriting the other. +Prototypes are global, so it's easy to get a conflict. If two libraries add a method `String.prototype.show`, then one of them will be overwriting the method of the other. So, generally, modifying a native prototype is considered a bad idea. ``` @@ -163,7 +163,7 @@ That's when we take a method from one object and copy it into another. Some methods of native prototypes are often borrowed. -For instance, if we're making an array-like object, we may want to copy some array methods to it. +For instance, if we're making an array-like object, we may want to copy some `Array` methods to it. E.g. diff --git a/2-ui/5-loading/02-script-async-defer/window-onbeforeunload.view/index.html b/2-ui/5-loading/02-script-async-defer/window-onbeforeunload.view/index.html deleted file mode 100644 index eacfda1f7..000000000 --- a/2-ui/5-loading/02-script-async-defer/window-onbeforeunload.view/index.html +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - - - - - Leave for EXAMPLE.COM - -