diff --git a/1-js/04-object-basics/02-object-copy/article.md b/1-js/04-object-basics/02-object-copy/article.md index e80f748ab..6739fc246 100644 --- a/1-js/04-object-basics/02-object-copy/article.md +++ b/1-js/04-object-basics/02-object-copy/article.md @@ -1,65 +1,65 @@ -# Object references and copying +# Referências e cópias de objetos -One of the fundamental differences of objects versus primitives is that objects are stored and copied "by reference", whereas primitive values: strings, numbers, booleans, etc -- are always copied "as a whole value". +Uma das diferenças fundamentais entre objetos e primitivos é que objetos são armazenados e copiados por "referência", enquanto valores primitivos: strings, números, booleanos, etc -- são sempre copiados "como um valor integral". -That's easy to understand if we look a bit under the hood of what happens when we copy a value. +Isso é fácil de entender se olharmos um pouco por debaixo dos panos do que acontece quando copiamos um valor. -Let's start with a primitive, such as a string. +Vamos começar com um primitivo, como uma string. -Here we put a copy of `message` into `phrase`: +Aqui fazemos uma cópia de `message` para `phrase` ```js let message = "Hello!"; let phrase = message; ``` -As a result we have two independent variables, each one storing the string `"Hello!"`. +Como resultado temos duas variáveis independentes, cada uma armazenando a string `"Hello!"` ![](variable-copy-value.svg) -Quite an obvious result, right? +Um resultado bastante óbvio, certo? -Objects are not like that. +Objetos não são assim. -**A variable assigned to an object stores not the object itself, but its "address in memory" -- in other words "a reference" to it.** +**Uma variável atribuída a um objeto armazena não o próprio objeto, mas sim o seu "endereço em memória" -- em outras palavras "uma referência" a ele.** -Let's look at an example of such a variable: +Vamos analisar o exemplo dessa variável ```js let user = { - name: "John" + name: "John", }; ``` -And here's how it's actually stored in memory: +E aqui é como ela está realmente armazenada na memória ![](variable-contains-reference.svg) -The object is stored somewhere in memory (at the right of the picture), while the `user` variable (at the left) has a "reference" to it. +O objeto é armazenado em algum lugar na memória (à direita da imagem), enquanto a variável `user` (à esquerda) possui uma referência a ele. -We may think of an object variable, such as `user`, like a sheet of paper with the address of the object on it. +Podemos pensar em uma variável de objeto, `user`, como uma folha de papel com o endereço do objeto escrito nela. -When we perform actions with the object, e.g. take a property `user.name`, the JavaScript engine looks at what's at that address and performs the operation on the actual object. +Quando realizamos ações com o objeto, por exemplo, acessar a propriedade `user.name`, o motor do Javascript verifica o que está nesse endereço e realiza a operação no objeto real. -Now here's why it's important. +Agora está aqui o motivo pelo qual isso é importante: -**When an object variable is copied, the reference is copied, but the object itself is not duplicated.** +**Quando uma variável de objeto é copiada, a referência é copiada, mas o próprio objeto não é duplicado** -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 storing a reference to the same object: +Agora temos duas variáveis, cada uma armazenando uma referência para o mesmo objeto: ![](variable-copy-reference.svg) -As you can see, there's still one object, but now with two variables that reference it. +Como você pode ver, ainda há apenas um objeto, porém agora com duas variáveis que o referenciam. -We can use either variable to access the object and modify its contents: +Podemos usar qualquer uma das variáveis para acessar o objeto e modificar o seu conteúdo: ```js run let user = { name: 'John' }; @@ -67,43 +67,43 @@ let user = { name: 'John' }; let admin = user; *!* -admin.name = 'Pete'; // changed by the "admin" reference +admin.name = 'Pete'; // alterado pela referência "admin" */!* -alert(*!*user.name*/!*); // 'Pete', changes are seen from the "user" reference +alert(*!*user.name*/!*); // 'Pete', alterações são vistas a partir da referência "user" ``` -It's as if we had a cabinet with two keys and used one of them (`admin`) to get into it and make changes. Then, if we later use another key (`user`), we are still opening the same cabinet and can access the changed contents. +É como se tivéssemos um armário com duas chaves e usado uma delas (`admin`) para abri-lo e fazer alterações. Então, se depois usarmos a outra chave (`user`), ainda estaremos abrindo o mesmo armário e podemos acessar o conteúdo alterado. -## Comparison by reference +## Comparação por referência -Two objects are equal only if they are the same object. +Dois objetos são iguais apenas se possuem a mesma referência. -For instance, here `a` and `b` reference the same object, thus they are equal: +Por exemplo, aqui `a` e `b` faz referência ao mesmo objeto, por isso eles são iguais: ```js run let a = {}; -let b = a; // copy the reference +let b = a; // copia a referência -alert( a == b ); // true, both variables reference the same object -alert( a === b ); // true +alert(a == b); // true, ambas as variáveis referenciam o mesmo objeto +alert(a === b); // true ``` -And here two independent objects are not equal, even though they look alike (both are empty): +E aqui, dois objetos independentes não são iguais, apesar deles pareceram iguais (ambos estão vazios): ```js run let a = {}; -let b = {}; // two independent objects +let b = {}; // dois objetos independentes -alert( a == b ); // false +alert(a == b); // false ``` -For comparisons like `obj1 > obj2` or for a comparison against a primitive `obj == 5`, objects are converted to primitives. We'll study how object conversions work very soon, but to tell the truth, such comparisons are needed very rarely -- usually they appear as a result of a programming mistake. +Para comparações como `obj1 > obj2` ou para uma comparação com um primitivo `obj == 5`, os objetos são convertidos em primitivos. Vamos estudar como as conversões de objetos funcionam muito em breve, mas, para ser honesto, tais comparações são necessárias muito raramente - geralmente, elas surgem como resultado de um erro de programação. -````smart header="Const objects can be modified" -An important side effect of storing objects as references is that an object declared as `const` *can* be modified. +````smart header="Objetos com const podem ser modificados" +Um efeito colateral importante de armazenar objetos como referência é que um objeto declarado como `const` *pode* ser modificado -For instance: +Por exemplo: ```js run const user = { @@ -117,22 +117,22 @@ user.name = "Pete"; // (*) alert(user.name); // Pete ``` -It might seem that the line `(*)` would cause an error, but it does not. The value of `user` is constant, it must always reference the same object, but properties of that object are free to change. +Pode parecer que a linha `(*)` causaria um erro, mas não causa. O valor de `user` é constante, ele deve sempre referenciar o mesmo objeto, porém as propriedades desse objeto são livres para mudar. -In other words, the `const user` gives an error only if we try to set `user=...` as a whole. +Em outras palavras, o `const user` gera um erro apenas se tentarmos definir `user=...` como um todo. -That said, if we really need to make constant object properties, it's also possible, but using totally different methods. We'll mention that in the chapter . +Dito isto, se realmente precisamos tornar as propriedades do objeto constantes, também é possível, porém usando métodos totalmente diferentes. Vamos mencionar isto no capítulo . ```` -## Cloning and merging, Object.assign [#cloning-and-merging-object-assign] +## Clonando e mesclando, Object.assign [#cloning-and-merging-object-assign] -So, copying an object variable creates one more reference to the same object. +Sim, copiar uma variável de objeto cria mais uma referência para o mesmo objeto. -But what if we need to duplicate an object? +Mas e se precisamos duplicar um objeto? -We can create a new object and replicate the structure of the existing one, by iterating over its properties and copying them on the primitive level. +Podemos criar um novo objeto e replicar a estrutura existente, iterando sobre suas propriedades e copiando-as no nível primitivo. -Like this: +Como neste exemplo: ```js run let user = { @@ -141,34 +141,34 @@ let user = { }; *!* -let clone = {}; // the new empty object +let clone = {}; // o novo objeto vazio -// let's copy all user properties into it +// vamos copiar todas as propriedades de usuário para ele for (let key in user) { clone[key] = user[key]; } */!* -// now clone is a fully independent object with the same content -clone.name = "Pete"; // changed the data in it +// agora clone é um objeto totalmente independente com o mesmo conteúdo +clone.name = "Pete"; // altera o dado nele -alert( user.name ); // still John in the original object +alert( user.name ); // Ainda será John no objeto original ``` -We can also use the method [Object.assign](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign). +Também podemos usar o método [Object.assign](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign). -The syntax is: +A sintaxe é: ```js -Object.assign(dest, ...sources) +Object.assign(dest, ...sources); ``` -- The first argument `dest` is a target object. -- Further arguments is a list of source objects. +- O primeiro argumento `dest` é um objeto destino. +- Os demais argumentos são uma lista de objetos de origem. -It copies the properties of all source objects into the target `dest`, and then returns it as the result. +Ele copia as propriedades de todos os objetos de origem para o destino `dest`, e em seguida, retorna-o como resultado. -For example, we have `user` object, let's add a couple of permissions to it: +Por exemplo, temos o objeto `user`, vamos adicionar um par de permissões a ele: ```js run let user = { name: "John" }; @@ -177,17 +177,17 @@ let permissions1 = { canView: true }; let permissions2 = { canEdit: true }; *!* -// copies all properties from permissions1 and permissions2 into user +// copia todas as 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 } alert(user.name); // John alert(user.canView); // true alert(user.canEdit); // true ``` -If the copied property name already exists, it gets overwritten: +Se o nome da propriedade copiada já existir, ela será sobrescrita. ```js run let user = { name: "John" }; @@ -197,7 +197,7 @@ Object.assign(user, { name: "Pete" }); alert(user.name); // now user = { name: "Pete" } ``` -We also can use `Object.assign` to perform a simple object cloning: +Também podemos usar `Object.assign` para realizar uma clonagem simples de objeto: ```js run let user = { @@ -213,55 +213,55 @@ alert(clone.name); // John alert(clone.age); // 30 ``` -Here it copies all properties of `user` into the empty object and returns it. +Aqui ele copia todas as propriedades de `user` para o objeto vazio e o retorna. -There are also other methods of cloning an object, e.g. using the [spread syntax](info:rest-parameters-spread) `clone = {...user}`, covered later in the tutorial. +Também há outros métodos de clonar um objeto, por exemplo, usando a [sintaxe de spread](info:rest-parameters-spread) `clone = {...user}`, abordado mais tarde no tutorial. -## Nested cloning +## Clonagem aninhada -Until now we assumed that all properties of `user` are primitive. But properties can be references to other objects. +Até agora, assumimos que todas as propriedades de `user` são primitivas. No entanto, propriedades podem ser referências a outros objetos. + +Como neste exemplo: -Like this: ```js run let user = { name: "John", sizes: { height: 182, - width: 50 - } + width: 50, + }, }; -alert( user.sizes.height ); // 182 +alert(user.sizes.height); // 182 ``` -Now it's not enough to copy `clone.sizes = user.sizes`, because `user.sizes` is an object, and will be copied by reference, so `clone` and `user` will share the same sizes: +Agora, não é suficiente copiar `clone.sizes = user.sizes`, porque `user.sizes` é um objeto e será copiado por referência, portanto `clone` e `user` irão compartilhar o mesmo objeto `sizes`: ```js run let user = { name: "John", sizes: { height: 182, - width: 50 - } + width: 50, + }, }; let clone = Object.assign({}, user); -alert( user.sizes === clone.sizes ); // true, same object +alert(user.sizes === clone.sizes); // true, mesmo objeto -// user and clone share sizes -user.sizes.width = 60; // change a property from one place -alert(clone.sizes.width); // 60, get the result from the other one +// user e clone compartilham sizes +user.sizes.width = 60; // altera uma propriedade de um local +alert(clone.sizes.width); // 60, obtém o resultado do outro ``` -To fix that and make `user` and `clone` truly separate objects, we should use a cloning loop that examines each value of `user[key]` and, if it's an object, then replicate its structure as well. That is called a "deep cloning" or "structured cloning". There's [structuredClone](https://developer.mozilla.org/en-US/docs/Web/API/structuredClone) method that implements deep cloning. - +Para corrigir isso e tornar `user` e `clone` objetos verdadeiramente separados, devemos usar um loop de clonagem que examina cada valor de `user[key]` e, se for um objeto, replica sua estrutura também. Isto é chamado "clonagem profunda" ou "clonagem estruturada". Existe o método [structuredClone](https://developer.mozilla.org/en-US/docs/Web/API/structuredClone) que implementa a clonagem profunda. ### structuredClone -The call `structuredClone(object)` clones the `object` with all nested properties. +A chamada `structuredClone(object)` clona o `object` com todas as propriedades aninhadas. -Here's how we can use it in our example: +Aqui está com podemos usá-lo em nosso exemplo: ```js run let user = { @@ -276,22 +276,22 @@ let user = { let clone = structuredClone(user); */!* -alert( user.sizes === clone.sizes ); // false, different objects +alert( user.sizes === clone.sizes ); // false, objetos diferentes -// user and clone are totally unrelated now -user.sizes.width = 60; // change a property from one place -alert(clone.sizes.width); // 50, not related +// Agora, user e clone são completamente independentes +user.sizes.width = 60; // altera uma propriedade de um local +alert(clone.sizes.width); // 50, não relacionado ``` -The `structuredClone` method can clone most data types, such as objects, arrays, primitive values. +O método `structuredClone` pode clonar a maioria dos tipos de dados, como objetos, arrays e valores primitivos. -It also supports circular references, when an object property references the object itself (directly or via a chain or references). +Ele também oferece suporte a referências circulares, quando uma propriedade de um objeto referencia o próprio objeto (diretamente ou através de uma cadeia de referências) -For instance: +Por exemplo: ```js run let user = {}; -// let's create a circular reference: +// vamos criar uma referência circular: // user.me references the user itself user.me = user; @@ -299,27 +299,27 @@ let clone = structuredClone(user); alert(clone.me === clone); // true ``` -As you can see, `clone.me` references the `clone`, not the `user`! So the circular reference was cloned correctly as well. +Como você pode ver `clone.me` faz referência a `clone`, não a `user`! Então a referência circular foi clonada corretamente também. -Although, there are cases when `structuredClone` fails. +No entanto, existem casos em que `structuredClone` falha. -For instance, when an object has a function property: +Por exemplo, quando um objeto possui uma propriedade que é uma função: ```js run // error structuredClone({ - f: function() {} + f: function () {}, }); ``` -Function properties aren't supported. +Propriedades que são funções não são suportadas. -To handle such complex cases we may need to use a combination of cloning methods, write custom code or, to not reinvent the wheel, take an existing implementation, for instance [_.cloneDeep(obj)](https://lodash.com/docs#cloneDeep) from the JavaScript library [lodash](https://lodash.com). +Para lidar com casos complexos, podemos precisar usar uma combinação de métodos de clonagem, escrever código personalizado ou, para não inventar a roda, usar uma implementação existente, como [\_.cloneDeep(obj)](https://lodash.com/docs#cloneDeep) da biblioteca JavaScript [lodash](https://lodash.com). -## Summary +## Resumo -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 itself. +Objetos são atribuídos e copiados por referência. Em outras palavras, uma variável armazena não o "valor do objeto", mas uma "referência" (endereço em memória) para o valor. Portanto, copiar a variável ou passá-la como argumento de uma função copia essa referência, não o objeto em si. -All operations via copied references (like adding/removing properties) are performed on the same single object. +Todas as operações feitas através de referências copiadas (como adição/remoção de propriedades) são realizadas no mesmo objeto único. -To make a "real copy" (a clone) we can use `Object.assign` for the so-called "shallow copy" (nested objects are copied by reference) or a "deep cloning" function `structuredClone` or use a custom cloning implementation, such as [_.cloneDeep(obj)](https://lodash.com/docs#cloneDeep). +Para fazer uma "cópia real" (um clone) podemos usar `Object.assign` caracterizando a chamada "cópia rasa" (objetos aninhados são copiados por referência) ou uma função `structuredClone` de "clonagem profunda" ou usar uma implementação de clonagem personalizada, como [\_.cloneDeep(obj)](https://lodash.com/docs#cloneDeep).