From f3fb7d2927a16e702ac7683957ff2981c86d31c5 Mon Sep 17 00:00:00 2001 From: odsantos Date: Tue, 22 Oct 2019 05:42:38 +0100 Subject: [PATCH 1/5] 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/5] 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 1666c67a3636bdc873e347999b0f6e0bd1930646 Mon Sep 17 00:00:00 2001 From: odsantos Date: Wed, 20 Nov 2019 00:28:29 +0100 Subject: [PATCH 3/5] translate object to primitive article --- .../05-object-toprimitive/article.md | 183 +++++++++--------- 1 file changed, 92 insertions(+), 91 deletions(-) diff --git a/1-js/04-object-basics/05-object-toprimitive/article.md b/1-js/04-object-basics/05-object-toprimitive/article.md index a44cf4f4d..1d67b24ee 100644 --- a/1-js/04-object-basics/05-object-toprimitive/article.md +++ b/1-js/04-object-basics/05-object-toprimitive/article.md @@ -1,93 +1,93 @@ -# Object to primitive conversion +# Conversão objeto para primitivo -What happens when objects are added `obj1 + obj2`, subtracted `obj1 - obj2` or printed using `alert(obj)`? +O que acontece quando objetos são adicionados `obj1 + obj2`, subtraídos `obj1 - obj2`, ou imprimidos usando `alert(obj)`? -There are special methods in objects that do the conversion. +Existem métodos especiais de objetos que fazem a conversão. -In the chapter we've seen the rules for numeric, string and boolean conversions of primitives. But we left a gap for objects. Now, as we know about methods and symbols it becomes possible to close it. +No capítulo vimos as regras para as conversões de primitivos para números, *strings* e boleanos. Mas, deixámos um intervalo para objetos. Agora, como já aprendemos sobre métodos e símbolos, torna-se possível fechá-lo. -For objects, there's no to-boolean conversion, because all objects are `true` in a boolean context. So there are only string and numeric conversions. +Para objetos, não há conversão para boleanos, porque todos os objetos são `true` num contexto boleano. Assim, apenas existem conversões para *strings* e números. -The numeric conversion happens when we subtract objects or apply mathematical functions. For instance, `Date` objects (to be covered in the chapter ) can be subtracted, and the result of `date1 - date2` is the time difference between two dates. +A conversão numérica acontece quando subtraímos objetos, ou aplicamos funções matemáticas. Por exemplo, os objetos `Date` (a serem estudados no capítulo ) podem ser subtraídos, e o resultado de `date1 - date2` é a diferença temporal entre as datas. -As for the string conversion -- it usually happens when we output an object like `alert(obj)` and in similar contexts. +Para a conversão para *string* -- ela geralmente acontece quando imprimimos um objeto, como em `alert(obj)`, e em contextos similares. -## ToPrimitive +## *ToPrimitive* -When an object is used in the context where a primitive is required, for instance, in an `alert` or mathematical operations, it's converted to a primitive value using the `ToPrimitive` algorithm ([specification](https://tc39.github.io/ecma262/#sec-toprimitive)). +Quando um objeto é utilizado num contexto onde um primitivo é necessário, por exemplo num `alert` ou em operações matemáticas, é convertido para um valor primitivo usando o algoritmo de `ToPrimitive` ([especificação em Inglês](https://tc39.github.io/ecma262/#sec-toprimitive)). -That algorithm allows us to customize the conversion using a special object method. +Esse algoritmo, permite-nos personalizar a conversão empregando um método de objeto especial. -Depending on the context, the conversion has a so-called "hint". +Dependendo do contexto, tem o que se chama de "palpite" (*hint*). -There are three variants: +Existem três variantes: `"string"` -: When an operation expects a string, for object-to-string conversions, like `alert`: +: Quando uma operação espera uma *string*, desta forma em conversões objeto-para-string, como em `alert`: ```js - // output + // saída alert(obj); - // using object as a property key + // empregando o objeto como chave de propriedade anotherObj[obj] = 123; ``` `"number"` -: When an operation expects a number, for object-to-number conversions, like maths: +: Quando uma operação espera um número, desta forma em conversões objeto-para-número, como em operações matemáticas: ```js - // explicit conversion + // conversão explícita let num = Number(obj); - // maths (except binary plus) - let n = +obj; // unary plus + // operações matemáticas (exceto o 'mais' binário) + let n = +obj; // 'mais' unário let delta = date1 - date2; - // less/greater comparison + // comparação maior/menor do que let greater = user1 > user2; ``` `"default"` -: Occurs in rare cases when the operator is "not sure" what type to expect. +: Ocorre em casos raros, quando o operador "não está certo" de que tipo esperar. - For instance, binary plus `+` can work both with strings (concatenates them) and numbers (adds them), so both strings and numbers would do. Or when an object is compared using `==` with a string, number or a symbol. + Por exemplo, o mais binário `+` pode trabalhar tanto com *strings* (concatenando-as) como com números (adicionando-os); portanto, quer *stings* como números são aceites. Ou, quando um objeto é comparado `==` a uma *string*, a um número, ou a um símbolo. ```js - // binary plus + // 'mais' binário let total = car1 + car2; - // obj == string/number/symbol + // obj == string/número/símbolo if (user == 1) { ... }; ``` - The greater/less operator `<>` can work with both strings and numbers too. Still, it uses "number" hint, not "default". That's for historical reasons. + Os operadores maior/menor do que `<>` também podem trabalhar com *strings* e números. Assim, aceitam o palpite "number", mas não o "default". Isso, por razões históricas. - In practice, all built-in objects except for one case (`Date` object, we'll learn it later) implement `"default"` conversion the same way as `"number"`. And probably we should do the same. + Na prática, todos os objetos incorporados (*built-in*), exceto num caso (o objeto `Date`, sobre o qual aprenderemos mais adiante) implementam a conversão `"default"` da mesma forma que a `"number"`. E, nós provavelmente deveriamos fazer o mesmo. -Please note -- there are only three hints. It's that simple. There is no "boolean" hint (all objects are `true` in boolean context) or anything else. And if we treat `"default"` and `"number"` the same, like most built-ins do, then there are only two conversions. +Por favor note -- existem apenas três palpites (*hints*). É assim tão simples. Não há um palpite para "boleano" (todos os objetos são `true` num contexto boleano), ou outro adicional. E, se não fizermos distinção entre `"default"` e `"number"`, como muitos incorporados (*built-ins*) não fazem, então apenas existem duas conversões. -**To do the conversion, JavaScript tries to find and call three object methods:** +**Para efetuar a conversão, JavaScript tenta encontrar e chama três métodos de objeto:** -1. Call `obj[Symbol.toPrimitive](hint)` if the method exists, -2. Otherwise if hint is `"string"` - - try `obj.toString()` and `obj.valueOf()`, whatever exists. -3. Otherwise if hint is `"number"` or `"default"` - - try `obj.valueOf()` and `obj.toString()`, whatever exists. +1. Chama `obj[Symbol.toPrimitive](hint)` se o método existir, +2. Senão, se o palpite (*hint*) for `"string"` + - tenta `obj.toString()` e `obj.valueOf()`, o que existir. +3. Senão, se o palpite for `"number"` ou `"default"` + - tenta `obj.valueOf()` e `obj.toString()`, o que existir. -## Symbol.toPrimitive +## *Symbol.toPrimitive* -Let's start from the first method. There's a built-in symbol named `Symbol.toPrimitive` that should be used to name the conversion method, like this: +Vamos começar pelo primeiro método. Existe um símbolo incorporado (*built-in*) chamado `Symbol.toPrimitive` que deverá ser utilizado para nomear o método de conversão, desta forma: ```js obj[Symbol.toPrimitive] = function(hint) { - // return a primitive value - // hint = one of "string", "number", "default" + // retorna um valor primitivo + // hint = "string", ou "number", ou "default" } ``` -For instance, here `user` object implements it: +Por exemplo, aqui o objeto `user` o implementa: ```js run let user = { @@ -95,54 +95,54 @@ let user = { money: 1000, [Symbol.toPrimitive](hint) { - alert(`hint: ${hint}`); - return hint == "string" ? `{name: "${this.name}"}` : this.money; + alert(`palpite: ${hint}`); + return hint == "string" ? `{nome: "${this.name}"}` : this.money; } }; -// conversions demo: -alert(user); // hint: string -> {name: "John"} -alert(+user); // hint: number -> 1000 -alert(user + 500); // hint: default -> 1500 +// demonstrações de conversões: +alert(user); // (palpite: string) -> {nome: "John"} +alert(+user); // (palpite: number) -> 1000 +alert(user + 500); // (palpite: default) -> 1500 ``` -As we can see from the code, `user` becomes a self-descriptive string or a money amount depending on the conversion. The single method `user[Symbol.toPrimitive]` handles all conversion cases. +Como podemos observar pelo código, `user` se torna numa *string* auto-descritiva ou numa quantia monetária, dependendo da conversão. Um único método `user[Symbol.toPrimitive]` trata de todos os casos de conversão. -## toString/valueOf +## *toString/valueOf* -Methods `toString` and `valueOf` come from ancient times. They are not symbols (symbols did not exist that long ago), but rather "regular" string-named methods. They provide an alternative "old-style" way to implement the conversion. +Os métodos `toString` e `valueOf` vêm de tempos antigos. Eles não são *symbols* (símbolos não existiam há tanto tempo), mas sim métodos com nomes "comuns". Eles fornecem uma alternativa "à moda antiga" para implementar a conversão. -If there's no `Symbol.toPrimitive` then JavaScript tries to find them and try in the order: +Se não houver `Symbol.toPrimitive` então JavaScript tenta encontrá-los na seguinte ordem: -- `toString -> valueOf` for "string" hint. -- `valueOf -> toString` otherwise. +- `toString -> valueOf`, para o palpite "string". +- `valueOf -> toString`, para os outros. -For instance, here `user` does the same as above using a combination of `toString` and `valueOf`: +Por exemplo, aqui `user` faz o mesmo que acima empregando uma combinação `toString` e `valueOf`: ```js run let user = { name: "John", money: 1000, - // for hint="string" + // para o palpite="string" toString() { - return `{name: "${this.name}"}`; + return `{nome: "${this.name}"}`; }, - // for hint="number" or "default" + // para o palpite="number" ou "default" valueOf() { return this.money; } }; -alert(user); // toString -> {name: "John"} -alert(+user); // valueOf -> 1000 -alert(user + 500); // valueOf -> 1500 +alert(user); // (toString) -> {nome: "John"} +alert(+user); // (valueOf) -> 1000 +alert(user + 500); // (valueOf) -> 1500 ``` -Often we want a single "catch-all" place to handle all primitive conversions. In this case we can implement `toString` only, like this: +Frequentemente, queremos um local "genérico" (*catch-all*) que trate de todas as conversões para primitivos. Neste caso, podemos apenas implementar `toString`, desta forma: ```js run let user = { @@ -153,40 +153,40 @@ let user = { } }; -alert(user); // toString -> John -alert(user + 500); // toString -> John500 +alert(user); // (toString) -> John +alert(user + 500); // (toString) -> John500 ``` -In the absence of `Symbol.toPrimitive` and `valueOf`, `toString` will handle all primitive conversions. +Na ausência de `Symbol.toPrimitive` e `valueOf`, `toString` tratará de todas as conversões para primitivos. -## ToPrimitive and ToString/ToNumber +## *ToPrimitive* e *ToString*/*ToNumber* -The important thing to know about all primitive-conversion methods is that they do not necessarily return the "hinted" primitive. +O importante a saber sobre todos os métodos de conversão para primitivos é que eles não necessariamente retornam o "palpite" de primitivo. -There is no control whether `toString()` returns exactly a string, or whether `Symbol.toPrimitive` method returns a number for a hint "number". +Não existe nenhum controlo sobre se `toString()` retorna exatamente uma *string*, ou se o método `Symbol.toPrimitive` retorna um número aquando de um palpite "number". -**The only mandatory thing: these methods must return a primitive.** +**A única coisa mandatória: estes métodos têm que retornar um primitivo.** -An operation that initiated the conversion gets that primitive, and then continues to work with it, applying further conversions if necessary. +Uma operação que precise da conversão obtem esse primitivo, e a seguir continua a trabalhar com ele, aplicando posteriores conversões se necessário. -For instance: +Por exemplo: -- Mathematical operations (except binary plus) perform `ToNumber` conversion: +- Operações matemáticas (exceto o 'mais' binário) executam uma conversão `ToNumber`: ```js run let obj = { - toString() { // toString handles all conversions in the absence of other methods + toString() { // toString trata de todas as conversões, na ausência de outros métodos return "2"; } }; - alert(obj * 2); // 4, ToPrimitive gives "2", then it becomes 2 + alert(obj * 2); // 4, ToPrimitive fornece "2", que se torna em 2 ``` -- Binary plus checks the primitive -- if it's a string, then it does concatenation, otherwise it performs `ToNumber` and works with numbers. +- O 'mais' binário verifica o primitivo -- se for uma *string*, então executa a concatenação, noutros casos recorre a `ToNumber` e trabalha com números. - String example: + Exemplo de string: ```js run let obj = { toString() { @@ -194,10 +194,11 @@ For instance: } }; - alert(obj + 2); // 22 (ToPrimitive returned string => concatenation) + alert(obj + 2); // 22 (ToPrimitive retornou uma string => concatenação) + ) ``` - Number example: + Exemplo de número: ```js run let obj = { toString() { @@ -205,32 +206,32 @@ For instance: } }; - alert(obj + 2); // 3 (ToPrimitive returned boolean, not string => ToNumber) + alert(obj + 2); // 3 (ToPrimitive retornou um boleano, não string => ToNumber) ``` ```smart header="Historical notes" -For historical reasons, methods `toString` or `valueOf` *should* return a primitive: if any of them returns an object, then there's no error, but that object is ignored (like if the method didn't exist). +Por razões históricas, os métodos `toString` e `valueOf` *deveriam* retornar um primitivo: se um deles retornar um objeto, não há erro, e esse objeto é ignorado (como se aqueles métodos não existissem). -In contrast, `Symbol.toPrimitive` *must* return a primitive, otherwise, there will be an error. +Em contraste, `Symbol.toPrimitive` *tem* de retornar um primitivo, senão haverá um erro. ``` -## Summary +## Sumário -The object-to-primitive conversion is called automatically by many built-in functions and operators that expect a primitive as a value. +A conversão objeto-para-primitivo, é automaticamente chamada por muitas funções e operadores incorpordos que esperam um primitivo como valor. -There are 3 types (hints) of it: -- `"string"` (for `alert` and other string conversions) -- `"number"` (for maths) -- `"default"` (few operators) +Existem 3 tipos (*hints*) dela: +- `"string"` (para `alert`, e outras conversões para *string*) +- `"number"` (para matemáticas) +- `"default"` (poucos operadores) -The specification describes explicitly which operator uses which hint. There are very few operators that "don't know what to expect" and use the `"default"` hint. Usually for built-in objects `"default"` hint is handled the same way as `"number"`, so in practice the last two are often merged together. +A especificação, explícitamente descreve que operador usa qual *hint*. Existem muitos poucos operadores que "não sabem o que esperar" e usam a *hint* `"default"`. Geralmente, para objetos incorporados a *hint* `"default"` é tratada da mesma forma que a `"number"`, pelo que por prática os últimos dois tipos são frequentemente fundidos. -The conversion algorithm is: +O algoritmo de conversão é: -1. Call `obj[Symbol.toPrimitive](hint)` if the method exists, -2. Otherwise if hint is `"string"` - - try `obj.toString()` and `obj.valueOf()`, whatever exists. -3. Otherwise if hint is `"number"` or `"default"` - - try `obj.valueOf()` and `obj.toString()`, whatever exists. +1. Chame `obj[Symbol.toPrimitive](hint)` se o método existir, +2. Senão, se o tipo é `"string"` + - tente `obj.toString()` e `obj.valueOf()`, o que existir. +3. Senão, se o tipo é `"number"` ou `"default"` + - tente `obj.valueOf()` e `obj.toString()`, o que existir. -In practice, it's often enough to implement only `obj.toString()` as a "catch-all" method for all conversions that return a "human-readable" representation of an object, for logging or debugging purposes. +Na prática, frequentemente basta implementar `obj.toString()` como método "genérico" para todas as conversões que retornem uma representão "legível" de um objeto, quer para propósitos de *logging* como de *debugging*. From 26f1fd0324f035091b63c03f98c163c337d2d6c1 Mon Sep 17 00:00:00 2001 From: Osvaldo Dias dos Santos Date: Wed, 11 Nov 2020 23:43:58 +0100 Subject: [PATCH 4/5] Update Object-toPrimitive translation. --- .../09-object-toprimitive/article.md | 204 ++++++++++-------- 1 file changed, 111 insertions(+), 93 deletions(-) diff --git a/1-js/04-object-basics/09-object-toprimitive/article.md b/1-js/04-object-basics/09-object-toprimitive/article.md index 1d67b24ee..b444d5757 100644 --- a/1-js/04-object-basics/09-object-toprimitive/article.md +++ b/1-js/04-object-basics/09-object-toprimitive/article.md @@ -1,41 +1,35 @@ # Conversão objeto para primitivo -O que acontece quando objetos são adicionados `obj1 + obj2`, subtraídos `obj1 - obj2`, ou imprimidos usando `alert(obj)`? +O que acontece quando objetos são adicionados `obj1 + obj2`, subtraídos `obj1 - obj2`, ou exibidos usando `alert(obj)`? -Existem métodos especiais de objetos que fazem a conversão. +Aí, os objetos são auto-convertidos para primitivos, e depois a operação é executada. -No capítulo vimos as regras para as conversões de primitivos para números, *strings* e boleanos. Mas, deixámos um intervalo para objetos. Agora, como já aprendemos sobre métodos e símbolos, torna-se possível fechá-lo. +No capítulo vimos regras para as conversões de primitivos para números, *strings* e booleanos. Mas, deixámos um intervalo para objetos. Agora, como já aprendemos sobre métodos e símbolos, se torna possível o fechar. -Para objetos, não há conversão para boleanos, porque todos os objetos são `true` num contexto boleano. Assim, apenas existem conversões para *strings* e números. - -A conversão numérica acontece quando subtraímos objetos, ou aplicamos funções matemáticas. Por exemplo, os objetos `Date` (a serem estudados no capítulo ) podem ser subtraídos, e o resultado de `date1 - date2` é a diferença temporal entre as datas. - -Para a conversão para *string* -- ela geralmente acontece quando imprimimos um objeto, como em `alert(obj)`, e em contextos similares. +1. Todos os objetos são `true` num contexto booleano. Apenas existem as conversões para *strings* e numérica. +2. A conversão numérica acontece quando subtraímos objetos, ou aplicamos funções matemáticas. Por exemplo, os objetos `Date` (a serem estudados no capítulo ) podem ser subtraídos, e o resultado de `date1 - date2` é a diferença temporal entre duas datas. +3. Para a conversão para *string* -- ela geralmente acontece quando exibimos um objeto, como em `alert(obj)`, e em contextos similares. ## *ToPrimitive* -Quando um objeto é utilizado num contexto onde um primitivo é necessário, por exemplo num `alert` ou em operações matemáticas, é convertido para um valor primitivo usando o algoritmo de `ToPrimitive` ([especificação em Inglês](https://tc39.github.io/ecma262/#sec-toprimitive)). - -Esse algoritmo, permite-nos personalizar a conversão empregando um método de objeto especial. +Nós, podemos afinar as conversões para *string* e numérica empregando métodos de objeto especiais. -Dependendo do contexto, tem o que se chama de "palpite" (*hint*). - -Existem três variantes: +Existem três variantes de conversão de tipo de dados, também chamadas de "sugestões" (*hints*), descritas na [especificação (em Inglês)](https://tc39.github.io/ecma262/#sec-toprimitive): `"string"` -: Quando uma operação espera uma *string*, desta forma em conversões objeto-para-string, como em `alert`: +: Para uma conversão objeto-string, quando estivermos a fazer uma operação num objeto mas à espera de uma *string* como resultado, a exemplo de `alert`: ```js - // saída + // exibindo alert(obj); - // empregando o objeto como chave de propriedade + // usando o objeto como chave de propriedade anotherObj[obj] = 123; ``` `"number"` -: Quando uma operação espera um número, desta forma em conversões objeto-para-número, como em operações matemáticas: +:Para uma conversão objeto-número, como em operações matemáticas: ```js // conversão explícita @@ -52,37 +46,43 @@ Existem três variantes: `"default"` : Ocorre em casos raros, quando o operador "não está certo" de que tipo esperar. - Por exemplo, o mais binário `+` pode trabalhar tanto com *strings* (concatenando-as) como com números (adicionando-os); portanto, quer *stings* como números são aceites. Ou, quando um objeto é comparado `==` a uma *string*, a um número, ou a um símbolo. + Por exemplo, o mais binário `+` pode trabalhar tanto com *strings* (as concatena) como com números (os adiciona), portanto quer *stings* como números são aceites. Assim, se um mais binário tiver um objeto como argumento, ele utiliza a sugestão `"default"` para o converter. + + De igual modo, se um objeto for comparado a uma *string*, a um número ou a um símbolo usando `==`, também não está claro que conversão deve ser feita, então a sugestão `"default"` é utilizada. ```js - // 'mais' binário + // o 'mais' binário usa a sugestão "default" let total = car1 + car2; - // obj == string/número/símbolo + // obj == number usa a sugestão "default" if (user == 1) { ... }; ``` - Os operadores maior/menor do que `<>` também podem trabalhar com *strings* e números. Assim, aceitam o palpite "number", mas não o "default". Isso, por razões históricas. + Os operadores de comparação maior/menor do que, tais como `<` `>`, também podem trabalhar tanto com *strings* como com números. Contudo, eles usam a sugestão `"number"`, não a `"default"`. Isto, por razões históricas. - Na prática, todos os objetos incorporados (*built-in*), exceto num caso (o objeto `Date`, sobre o qual aprenderemos mais adiante) implementam a conversão `"default"` da mesma forma que a `"number"`. E, nós provavelmente deveriamos fazer o mesmo. + Na prática, na verdade, nós não precisamos de nos lembrar desses pequenos detalhes, porque todos os objetos incorporados, exceto num caso (o objeto `Date`, sobre o qual iremos aprender mais adiante) implementam a conversão `"default"` da mesma forma que a `"number"`. E nós podemos fazer o mesmo. -Por favor note -- existem apenas três palpites (*hints*). É assim tão simples. Não há um palpite para "boleano" (todos os objetos são `true` num contexto boleano), ou outro adicional. E, se não fizermos distinção entre `"default"` e `"number"`, como muitos incorporados (*built-ins*) não fazem, então apenas existem duas conversões. +```smart header="Nenhuma sugestão `\"boolean\"`" +Por favor note -- existem apenas três sugestões (*hints*). É assim tão simples. -**Para efetuar a conversão, JavaScript tenta encontrar e chama três métodos de objeto:** +Não há uma sugestão para "booleano" (todos os objetos são `true` num contexto booleano), nem outras sugestões. E, se não fizermos distinção entre `"default"` e `"number"`, como muitos incorporados não fazem, então apenas existem duas conversões. +``` + +**Para efetuar a conversão, o JavaScript tenta encontrar e chama três métodos de objeto:** 1. Chama `obj[Symbol.toPrimitive](hint)` se o método existir, -2. Senão, se o palpite (*hint*) for `"string"` +2. Senão, se a sugestão for `"string"` - tenta `obj.toString()` e `obj.valueOf()`, o que existir. -3. Senão, se o palpite for `"number"` ou `"default"` +3. Senão, se a sugestão for `"number"` ou `"default"` - tenta `obj.valueOf()` e `obj.toString()`, o que existir. ## *Symbol.toPrimitive* -Vamos começar pelo primeiro método. Existe um símbolo incorporado (*built-in*) chamado `Symbol.toPrimitive` que deverá ser utilizado para nomear o método de conversão, desta forma: +Vamos começar pelo primeiro método. Existe um símbolo incorporado chamado `Symbol.toPrimitive` que deverá ser utilizado para dar nome ao método de conversão, desta forma: ```js obj[Symbol.toPrimitive] = function(hint) { - // retorna um valor primitivo + // tem de retornar um valor primitivo // hint = "string", ou "number", ou "default" } ``` @@ -95,54 +95,78 @@ let user = { money: 1000, [Symbol.toPrimitive](hint) { - alert(`palpite: ${hint}`); + alert(`sugestão: ${hint}`); return hint == "string" ? `{nome: "${this.name}"}` : this.money; } }; -// demonstrações de conversões: -alert(user); // (palpite: string) -> {nome: "John"} -alert(+user); // (palpite: number) -> 1000 -alert(user + 500); // (palpite: default) -> 1500 +// exemplos de conversões: +alert(user); // sugestão: string -> {nome: "John"} +alert(+user); // sugestão: number -> 1000 +alert(user + 500); // sugestão: default -> 1500 ``` -Como podemos observar pelo código, `user` se torna numa *string* auto-descritiva ou numa quantia monetária, dependendo da conversão. Um único método `user[Symbol.toPrimitive]` trata de todos os casos de conversão. +Como podemos ver pelo código, `user` se torna numa *string* auto-descritiva ou numa quantia monetária, dependendo da conversão. Um único método `user[Symbol.toPrimitive]` trata de todos os casos de conversão. ## *toString/valueOf* Os métodos `toString` e `valueOf` vêm de tempos antigos. Eles não são *symbols* (símbolos não existiam há tanto tempo), mas sim métodos com nomes "comuns". Eles fornecem uma alternativa "à moda antiga" para implementar a conversão. -Se não houver `Symbol.toPrimitive` então JavaScript tenta encontrá-los na seguinte ordem: +Se não houver `Symbol.toPrimitive` então o JavaScript os tenta encontrar na seguinte ordem: + +- `toString -> valueOf` para a sugestão "string". +- `valueOf -> toString` para as outras. + +Estes métodos têm de retornar um valor primitivo. Se `toString` ou `valueOf` retornarem um objeto, este é ignorado (como se o método não existisse). + +Por padrão, um objeto simples possui os seguintes métodos `toString` e `valueOf`: + +- O método `toString` retorna uma string `"[object Object]"`. +- O método `valueOf` retorna o próprio objeto. + +Aqui está um exemplo: + +```js run +let user = {name: "John"}; + +alert(user); // [object Object] +alert(user.valueOf() === user); // true +``` + +Assim, se tentarmos usar um objeto como uma *string*, como em `alert` ou similar, então por padrão nós iremos ver `[object Object]`. + +E o valor padrão de `valueOf` está aqui mencionado apenas por completude, para evitar qualquer confusão. Como você pode ver, ele retorna o próprio objeto, e por isso este é ignorado. Não me pergunte porquê, é por razões históricas. Então, podemos assumir que o método não existe. -- `toString -> valueOf`, para o palpite "string". -- `valueOf -> toString`, para os outros. +Vamos implementar estes métodos. -Por exemplo, aqui `user` faz o mesmo que acima empregando uma combinação `toString` e `valueOf`: +Por exemplo, aqui `user` faz o mesmo que acima usando uma combinação de `toString` e `valueOf` em vez de `Symbol.toPrimitive`: ```js run let user = { name: "John", money: 1000, - // para o palpite="string" + // para hint="string" toString() { return `{nome: "${this.name}"}`; }, - // para o palpite="number" ou "default" + // para hint="number" ou "default" valueOf() { return this.money; } }; -alert(user); // (toString) -> {nome: "John"} -alert(+user); // (valueOf) -> 1000 -alert(user + 500); // (valueOf) -> 1500 +alert(user); // toString -> {nome: "John"} +alert(+user); // valueOf -> 1000 +alert(user + 500); // valueOf -> 1500 ``` -Frequentemente, queremos um local "genérico" (*catch-all*) que trate de todas as conversões para primitivos. Neste caso, podemos apenas implementar `toString`, desta forma: +Como podemos ver, o resultado é o mesmo que no exemplo anterior com `Symbol.toPrimitive`. + +Frequentemente, queremos um único local "genérico" (*catch-all*) para tratar de todas as conversões para primitivos. Nesse caso, podemos só implementar `toString`, desta forma: ```js run let user = { @@ -153,85 +177,79 @@ let user = { } }; -alert(user); // (toString) -> John -alert(user + 500); // (toString) -> John500 +alert(user); // toString -> John +alert(user + 500); // toString -> John500 ``` -Na ausência de `Symbol.toPrimitive` e `valueOf`, `toString` tratará de todas as conversões para primitivos. - +Na ausência de `Symbol.toPrimitive` e `valueOf`, `toString` irá tratar de todas as conversões para primitivos. -## *ToPrimitive* e *ToString*/*ToNumber* +## Tipos de dados retornados -O importante a saber sobre todos os métodos de conversão para primitivos é que eles não necessariamente retornam o "palpite" de primitivo. +O importante a saber sobre todos os métodos de conversão para primitivos, é que eles não necessariamente retornam o primitivo "sugerido". -Não existe nenhum controlo sobre se `toString()` retorna exatamente uma *string*, ou se o método `Symbol.toPrimitive` retorna um número aquando de um palpite "number". +Não existe nenhum controlo sobre se `toString()` retorna exatamente uma *string*, ou se o método `Symbol.toPrimitive` retorna um número para uma sugestão `"number"`. -**A única coisa mandatória: estes métodos têm que retornar um primitivo.** +A única coisa mandatória: estes métodos têm de retornar um primitivo, não um objeto. -Uma operação que precise da conversão obtem esse primitivo, e a seguir continua a trabalhar com ele, aplicando posteriores conversões se necessário. +```smart header="Notas históricas" +Por razões históricas, se `toString` ou `valueOf` retornarem um objeto, não haverá erro, mas esse valor é ignorado (como se o método não existisse). Isto, porque antigamente não havia um bom conceito de "erro" em JavaScript. -Por exemplo: +Em contraste, `Symbol.toPrimitive` *tem de* retornar um primitivo, caso contrário haverá um erro. +``` -- Operações matemáticas (exceto o 'mais' binário) executam uma conversão `ToNumber`: +## Outras conversões - ```js run - let obj = { - toString() { // toString trata de todas as conversões, na ausência de outros métodos - return "2"; - } - }; +Como já sabemos, muitos operadores e funções executam conversões de tipo de dados, por ex. a multiplicação `*` converte os operandos para números. - alert(obj * 2); // 4, ToPrimitive fornece "2", que se torna em 2 - ``` +Se, nós fornecermos um objeto como um argumento, então haverão dois estágios: +1. O objeto é convertido para um primitivo (usando as regras descritas acima). +2. Se, o primitivo resultante não for do tipo certo, é convertido. -- O 'mais' binário verifica o primitivo -- se for uma *string*, então executa a concatenação, noutros casos recorre a `ToNumber` e trabalha com números. +Por exemplo: - Exemplo de string: - ```js run - let obj = { - toString() { - return "2"; - } - }; +```js run +let obj = { + // toString trata de todas as conversões, na ausência de outros métodos + toString() { + return "2"; + } +}; - alert(obj + 2); // 22 (ToPrimitive retornou uma string => concatenação) - ) - ``` +alert(obj * 2); // 4, objeto convertido para primitivo "2", então a multiplicação o transformou num número +``` - Exemplo de número: - ```js run - let obj = { - toString() { - return true; - } - }; +1. A multiplicação `obj * 2` primeiro converte o objeto para primitivo (esse é a *string* `"2"`). +2. A seguir, `"2" * 2` se torna em `2 * 2` (a *string* é convertida para número). - alert(obj + 2); // 3 (ToPrimitive retornou um boleano, não string => ToNumber) - ``` +Numa situação semelhante, o 'mais' binário irá concatenar *strings*, pois ele com satisfação aceita uma *string*. -```smart header="Historical notes" -Por razões históricas, os métodos `toString` e `valueOf` *deveriam* retornar um primitivo: se um deles retornar um objeto, não há erro, e esse objeto é ignorado (como se aqueles métodos não existissem). +```js run +let obj = { + toString() { + return "2"; + } +}; -Em contraste, `Symbol.toPrimitive` *tem* de retornar um primitivo, senão haverá um erro. +alert(obj + 2); // 22 ("2" + 2), a conversão para primitivo retornou uma string => concatenação ``` ## Sumário -A conversão objeto-para-primitivo, é automaticamente chamada por muitas funções e operadores incorpordos que esperam um primitivo como valor. +A conversão objeto-para-primitivo, é automaticamente chamada por muitas funções e operadores incorporados que esperam um primitivo como valor. Existem 3 tipos (*hints*) dela: -- `"string"` (para `alert`, e outras conversões para *string*) +- `"string"` (para `alert`, e outras operações que precisam duma *string*) - `"number"` (para matemáticas) - `"default"` (poucos operadores) -A especificação, explícitamente descreve que operador usa qual *hint*. Existem muitos poucos operadores que "não sabem o que esperar" e usam a *hint* `"default"`. Geralmente, para objetos incorporados a *hint* `"default"` é tratada da mesma forma que a `"number"`, pelo que por prática os últimos dois tipos são frequentemente fundidos. +A especificação, explícitamente descreve que operador usa que *hint*. Existem muitos poucos operadores que "não sabem o que esperar" e usam a *hint* `"default"`. Geralmente, para objetos incorporados a *hint* `"default"` é tratada da mesma forma que a `"number"`, pelo que na prática os últimos dois tipos são frequentemente fundidos. O algoritmo de conversão é: 1. Chame `obj[Symbol.toPrimitive](hint)` se o método existir, -2. Senão, se o tipo é `"string"` +2. Senão, se *hint* for `"string"` - tente `obj.toString()` e `obj.valueOf()`, o que existir. -3. Senão, se o tipo é `"number"` ou `"default"` +3. Senão, se o *hint* for `"number"` ou `"default"` - tente `obj.valueOf()` e `obj.toString()`, o que existir. -Na prática, frequentemente basta implementar `obj.toString()` como método "genérico" para todas as conversões que retornem uma representão "legível" de um objeto, quer para propósitos de *logging* como de *debugging*. +Na prática, frequentemente basta apenas implementar `obj.toString()` como método "genérico" para todas as conversões que retornem uma representação "legível" de um objeto, quer para propósitos de *logging* como de *debugging*. From 940c545cdccd5accd059f255c1282f661b4943f1 Mon Sep 17 00:00:00 2001 From: Osvaldo Dias dos Santos Date: Tue, 13 Jul 2021 13:45:29 +0100 Subject: [PATCH 5/5] Resolve conflicts --- .../09-object-toprimitive/article.md | 112 +++++++++++------- 1 file changed, 67 insertions(+), 45 deletions(-) diff --git a/1-js/04-object-basics/09-object-toprimitive/article.md b/1-js/04-object-basics/09-object-toprimitive/article.md index b444d5757..654eae348 100644 --- a/1-js/04-object-basics/09-object-toprimitive/article.md +++ b/1-js/04-object-basics/09-object-toprimitive/article.md @@ -3,22 +3,39 @@ O que acontece quando objetos são adicionados `obj1 + obj2`, subtraídos `obj1 - obj2`, ou exibidos usando `alert(obj)`? -Aí, os objetos são auto-convertidos para primitivos, e depois a operação é executada. +O JavaScript não permite customizar com exatidão como operadores devem trabalhar com objetos. Ao contrário de outras linguagens de programação como Ruby ou C++, nós não podemos implementar um método de objeto especial para lidar com uma adição (ou outras operações). -No capítulo vimos regras para as conversões de primitivos para números, *strings* e booleanos. Mas, deixámos um intervalo para objetos. Agora, como já aprendemos sobre métodos e símbolos, se torna possível o fechar. +Para tais operações, os objetos são auto-convertidos para primitivos, e depois a operação é executada sobre tais primitivos e o resultado é um valor primitivo. -1. Todos os objetos são `true` num contexto booleano. Apenas existem as conversões para *strings* e numérica. -2. A conversão numérica acontece quando subtraímos objetos, ou aplicamos funções matemáticas. Por exemplo, os objetos `Date` (a serem estudados no capítulo ) podem ser subtraídos, e o resultado de `date1 - date2` é a diferença temporal entre duas datas. -3. Para a conversão para *string* -- ela geralmente acontece quando exibimos um objeto, como em `alert(obj)`, e em contextos similares. +Esta é uma importante limitação, pois o resultado de `obj1 + obj2` não pode ser um outro objeto. -## *ToPrimitive* +Por ex., nós não podemos criar objetos representando vetores ou matrizes (ou conquistas, ou outros), adicioná-los e esperar um objecto "soma" como resultado. Tais efeitos especiais estão automáticamente "fora de questão". -Nós, podemos afinar as conversões para *string* e numérica empregando métodos de objeto especiais. +Portanto, como nós não podemos fazer muito neste campo, não há operações matemáticas com objetos em projetos reais. Quando isto acontece, geralmente é devido a um erro no código. -Existem três variantes de conversão de tipo de dados, também chamadas de "sugestões" (*hints*), descritas na [especificação (em Inglês)](https://tc39.github.io/ecma262/#sec-toprimitive): +Neste capítulo, vamos estudar como um objeto é convertido para primitivo, e como o customizar. + +Nós temos dois objetivos: + +1. Isto nos irá permitir perceber o que se passa no caso de erros de código, quando uma operação ocorrer acidentalmente. +2. Exceções, onde tais operações são possíveis e têm um bom resultado. Por ex., subtraindo ou comparando datas (objetos `Date`). Vamos vê-las mais adiante. + +## Regras de conversão + +No capítulo nós vimos regras para as conversões de primitivos para números, para *strings* e para booleanos. Mas, deixámos um espaço aberto para objetos. Agora, como já aprendemos sobre métodos e símbolos, é possível fechá-lo. + +1. Todos os objetos são `true` num contexto booleano. Assim, apenas existem as conversões para *string* e numérica. +2. A conversão numérica acontece quando subtraímos objetos, ou aplicamos outras funções matemáticas. Por exemplo, os objetos `Date` (a serem estudados no capítulo ) podem ser subtraídos, e o resultado de `date1 - date2` é a diferença temporal entre duas datas. +3. A conversão para *string* -- geralmente acontece quando exibimos um objeto, como em `alert(obj)`, e em contextos similares. + +Nós podemos afinar as conversões para *string* e numérica empregando métodos especiais de objeto. + +Existem três variantes para a conversão de tipo de dados, que ocorrem em várias situações. + +Elas são chamadas de "sugestões" (*hints*), como descrito na [especificação (em Inglês)](https://tc39.github.io/ecma262/#sec-toprimitive): `"string"` -: Para uma conversão objeto-string, quando estivermos a fazer uma operação num objeto mas à espera de uma *string* como resultado, a exemplo de `alert`: +: Para uma conversão objeto-string, quando estivermos a fazer uma operação num objeto mas à espera de uma *string* como resultado, a exemplo de em `alert`: ```js // exibindo @@ -28,8 +45,8 @@ Existem três variantes de conversão de tipo de dados, também chamadas de "sug anotherObj[obj] = 123; ``` -`"number"` -:Para uma conversão objeto-número, como em operações matemáticas: +`"number" (número)` +: Para uma conversão objeto-número, a exemplo de em operações matemáticas: ```js // conversão explícita @@ -43,50 +60,53 @@ Existem três variantes de conversão de tipo de dados, também chamadas de "sug let greater = user1 > user2; ``` -`"default"` +`"default" (padrão)` : Ocorre em casos raros, quando o operador "não está certo" de que tipo esperar. - Por exemplo, o mais binário `+` pode trabalhar tanto com *strings* (as concatena) como com números (os adiciona), portanto quer *stings* como números são aceites. Assim, se um mais binário tiver um objeto como argumento, ele utiliza a sugestão `"default"` para o converter. + Por exemplo, o mais binário `+` pode trabalhar tanto com *strings* (concatenando-as) como com números (adicionando-os), portanto quer *stings* como números são aceites. Assim, se um 'mais' binário tiver um objeto como argumento, ele utiliza a sugestão `"default"` para o converter. - De igual modo, se um objeto for comparado a uma *string*, a um número ou a um símbolo usando `==`, também não está claro que conversão deve ser feita, então a sugestão `"default"` é utilizada. + De igual modo, se um objeto for comparado usando `==`, quer a uma *string*, como a um número ou a um símbolo, também não está claro que conversão deve ser feita, então a sugestão `"default"` é utilizada. ```js // o 'mais' binário usa a sugestão "default" - let total = car1 + car2; + let total = obj1 + obj2; - // obj == number usa a sugestão "default" + // 'obj == number' usa a sugestão "default" if (user == 1) { ... }; ``` Os operadores de comparação maior/menor do que, tais como `<` `>`, também podem trabalhar tanto com *strings* como com números. Contudo, eles usam a sugestão `"number"`, não a `"default"`. Isto, por razões históricas. - Na prática, na verdade, nós não precisamos de nos lembrar desses pequenos detalhes, porque todos os objetos incorporados, exceto num caso (o objeto `Date`, sobre o qual iremos aprender mais adiante) implementam a conversão `"default"` da mesma forma que a `"number"`. E nós podemos fazer o mesmo. + Na prática, na verdade, nós não precisamos de nos lembrar desses pequenos detalhes, porque todos os objetos incorporados à linguagem, exceto num caso (o objeto `Date`, sobre o qual iremos aprender mais adiante) implementam a conversão `"default"` da mesma maneira que a `"number"`. E nós podemos fazer o mesmo. ```smart header="Nenhuma sugestão `\"boolean\"`" -Por favor note -- existem apenas três sugestões (*hints*). É assim tão simples. +Por favor note -- existem apenas três sugestões (*hints*). É tão simples assim. -Não há uma sugestão para "booleano" (todos os objetos são `true` num contexto booleano), nem outras sugestões. E, se não fizermos distinção entre `"default"` e `"number"`, como muitos incorporados não fazem, então apenas existem duas conversões. +Não há uma sugestão para "booleano" (todos os objetos são `true` num contexto booleano), nem outras sugestões. E, se não fizermos distinção entre `"default"` e `"number"`, como muitos incorporados à linguagem não fazem, então apenas existem duas conversões. ``` -**Para efetuar a conversão, o JavaScript tenta encontrar e chama três métodos de objeto:** +**Para fazer a conversão, o JavaScript tenta encontrar e chamar três métodos de objeto:** -1. Chama `obj[Symbol.toPrimitive](hint)` se o método existir, +1. Chama `obj[Symbol.toPrimitive](hint)` - o método com a chave simbólica `Symbol.toPrimitive` (símbolo da linguagem), se o método existir, 2. Senão, se a sugestão for `"string"` - - tenta `obj.toString()` e `obj.valueOf()`, o que existir. + - tenta `obj.toString()` ou `obj.valueOf()`, o que existir. 3. Senão, se a sugestão for `"number"` ou `"default"` - - tenta `obj.valueOf()` e `obj.toString()`, o que existir. + - tenta `obj.valueOf()` ou `obj.toString()`, o que existir. ## *Symbol.toPrimitive* -Vamos começar pelo primeiro método. Existe um símbolo incorporado chamado `Symbol.toPrimitive` que deverá ser utilizado para dar nome ao método de conversão, desta forma: +Vamos começar pelo primeiro método. Existe um símbolo incorporado à linguagem, chamado `Symbol.toPrimitive`, que deve ser utilizado para atribuir um nome ao método de conversão, desta forma: ```js obj[Symbol.toPrimitive] = function(hint) { - // tem de retornar um valor primitivo + // aqui se coloca o código para converter este objeto para primitivo, + // ele tem de retornar um valor primitivo // hint = "string", ou "number", ou "default" } ``` +Se o método `Symbol.toPrimitive` existir, ele é utilizado para todas as sugestões, e nenhum mais outro método é necessário. + Por exemplo, aqui o objeto `user` o implementa: ```js run @@ -111,16 +131,16 @@ Como podemos ver pelo código, `user` se torna numa *string* auto-descritiva ou ## *toString/valueOf* -Os métodos `toString` e `valueOf` vêm de tempos antigos. Eles não são *symbols* (símbolos não existiam há tanto tempo), mas sim métodos com nomes "comuns". Eles fornecem uma alternativa "à moda antiga" para implementar a conversão. +Se não houver `Symbol.toPrimitive` então o JavaScript tenta encontrar os métodos `toString` ou `valueOf`: -Se não houver `Symbol.toPrimitive` então o JavaScript os tenta encontrar na seguinte ordem: +- Para a sugestão "string": `toString`, e se ele não existir, então `valueOf` (portanto, `toString` tem prioridade em conversões para *string*). +- Para outras sugestões: `valueOf`, e se ele não existir, então `toString` (portanto, `valueOf` tem prioridade em operações matemáticas). -- `toString -> valueOf` para a sugestão "string". -- `valueOf -> toString` para as outras. +Os métodos `toString` e `valueOf` vêm de tempos antigos. Eles não são *symbols* (símbolos não existiam há tanto tempo), mas sim métodos com nomes "comuns". Eles fornecem uma alternativa "à moda antiga" para implementar a conversão. -Estes métodos têm de retornar um valor primitivo. Se `toString` ou `valueOf` retornarem um objeto, este é ignorado (como se o método não existisse). +Estes métodos têm de retornar um valor primitivo. Se `toString` ou `valueOf` retornar um objeto, este é ignorado (é o mesmo caso os métodos não existam). -Por padrão, um objeto simples possui os seguintes métodos `toString` e `valueOf`: +Por padrão, um objeto simples possui os métodos `toString` e `valueOf`: - O método `toString` retorna uma string `"[object Object]"`. - O método `valueOf` retorna o próprio objeto. @@ -136,9 +156,9 @@ alert(user.valueOf() === user); // true Assim, se tentarmos usar um objeto como uma *string*, como em `alert` ou similar, então por padrão nós iremos ver `[object Object]`. -E o valor padrão de `valueOf` está aqui mencionado apenas por completude, para evitar qualquer confusão. Como você pode ver, ele retorna o próprio objeto, e por isso este é ignorado. Não me pergunte porquê, é por razões históricas. Então, podemos assumir que o método não existe. +E o método padrão `valueOf` está aqui mencionado apenas por completude, para evitar qualquer confusão. Como você pode ver, ele retorna o próprio objeto, e por isso é ignorado. Não me pergunte porquê, é assim por razões históricas. Então, podemos assumir que o método não exista. -Vamos implementar estes métodos. +Vamos implementar estes métodos para customizar a conversão. Por exemplo, aqui `user` faz o mesmo que acima usando uma combinação de `toString` e `valueOf` em vez de `Symbol.toPrimitive`: @@ -183,7 +203,7 @@ alert(user + 500); // toString -> John500 Na ausência de `Symbol.toPrimitive` e `valueOf`, `toString` irá tratar de todas as conversões para primitivos. -## Tipos de dados retornados +### Uma conversão pode retornar qualquer tipo primitivo O importante a saber sobre todos os métodos de conversão para primitivos, é que eles não necessariamente retornam o primitivo "sugerido". @@ -192,17 +212,17 @@ Não existe nenhum controlo sobre se `toString()` retorna exatamente uma *string A única coisa mandatória: estes métodos têm de retornar um primitivo, não um objeto. ```smart header="Notas históricas" -Por razões históricas, se `toString` ou `valueOf` retornarem um objeto, não haverá erro, mas esse valor é ignorado (como se o método não existisse). Isto, porque antigamente não havia um bom conceito de "erro" em JavaScript. +Por razões históricas, se `toString` ou `valueOf` retornar um objeto, não haverá erro, mas esse valor é ignorado (como se o método não existisse). Isto, porque antigamente não havia um bom conceito de "erro" em JavaScript. Em contraste, `Symbol.toPrimitive` *tem de* retornar um primitivo, caso contrário haverá um erro. ``` ## Outras conversões -Como já sabemos, muitos operadores e funções executam conversões de tipo de dados, por ex. a multiplicação `*` converte os operandos para números. +Como já sabemos, muitos operadores e funções executam conversões de tipo de dados. Por ex., a multiplicação `*` converte os operandos para números. -Se, nós fornecermos um objeto como um argumento, então haverão dois estágios: -1. O objeto é convertido para um primitivo (usando as regras descritas acima). +Se, nós fornecermos um objeto como argumento, então haverão dois estágios: +1. O objeto é convertido para um primitivo (usando as regras acima descritas). 2. Se, o primitivo resultante não for do tipo certo, é convertido. Por exemplo: @@ -215,13 +235,13 @@ let obj = { } }; -alert(obj * 2); // 4, objeto convertido para primitivo "2", então a multiplicação o transformou num número +alert(obj * 2); // 4, objeto convertido para primitivo "2", então a multiplicação o transforma num número ``` 1. A multiplicação `obj * 2` primeiro converte o objeto para primitivo (esse é a *string* `"2"`). 2. A seguir, `"2" * 2` se torna em `2 * 2` (a *string* é convertida para número). -Numa situação semelhante, o 'mais' binário irá concatenar *strings*, pois ele com satisfação aceita uma *string*. +Numa situação semelhante, o 'mais' binário irá concatenar *strings*, pois ele com satisfação aceita *strings*. ```js run let obj = { @@ -235,21 +255,23 @@ alert(obj + 2); // 22 ("2" + 2), a conversão para primitivo retornou uma string ## Sumário -A conversão objeto-para-primitivo, é automaticamente chamada por muitas funções e operadores incorporados que esperam um primitivo como valor. +A conversão objeto-para-primitivo, é automaticamente chamada por muitas funções e operadores incorporados à linguagem que esperam um primitivo como valor. Existem 3 tipos (*hints*) dela: - `"string"` (para `alert`, e outras operações que precisam duma *string*) - `"number"` (para matemáticas) - `"default"` (poucos operadores) -A especificação, explícitamente descreve que operador usa que *hint*. Existem muitos poucos operadores que "não sabem o que esperar" e usam a *hint* `"default"`. Geralmente, para objetos incorporados a *hint* `"default"` é tratada da mesma forma que a `"number"`, pelo que na prática os últimos dois tipos são frequentemente fundidos. +A especificação, explícitamente descreve que operador usa que tipo. Existem muitos poucos operadores que "não sabem o que esperar" e usam o tipo `"default"`. Geralmente, para objetos incorporados à linguagem o tipo `"default"` é tratado da mesma maneira que o `"number"`, pelo que na prática os últimos dois tipos acima são frequentemente fundidos. O algoritmo de conversão é: 1. Chame `obj[Symbol.toPrimitive](hint)` se o método existir, 2. Senão, se *hint* for `"string"` - - tente `obj.toString()` e `obj.valueOf()`, o que existir. + - tente `obj.toString()` ou `obj.valueOf()`, o que existir. 3. Senão, se o *hint* for `"number"` ou `"default"` - - tente `obj.valueOf()` e `obj.toString()`, o que existir. + - tente `obj.valueOf()` ou `obj.toString()`, o que existir. + +Na prática, frequentemente basta apenas implementar `obj.toString()` como método "genérico" para conversões para *string* que deveriam retornar uma representação "legível" de um objeto, quer para propósitos de *logging* como de *debugging*. -Na prática, frequentemente basta apenas implementar `obj.toString()` como método "genérico" para todas as conversões que retornem uma representação "legível" de um objeto, quer para propósitos de *logging* como de *debugging*. +Para operações matemáticas, o JavaScript não provê uma forma de "customizá-las" usando métodos, assim projetos na vida real raramente as usam com objetos.