Repository navigation
Property getters and setters #480
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -1,31 +1,31 @@ | ||||||
|
|
||||||
| # Property getters and setters | ||||||
| # Getters e setters de propriedades | ||||||
|
|
||||||
| There are two kinds of object properties. | ||||||
| Existem dois tipos de propriedades de objeto. | ||||||
|
|
||||||
| The first kind is *data properties*. We already know how to work with them. All properties that we've been using until now were data properties. | ||||||
| O primeiro tipo são as *propriedades de dados*. Já sabemos como trabalhar com elas. Todas as propriedades que usamos até agora eram propriedades de dados. | ||||||
|
|
||||||
| The second type of property is something new. It's an *accessor property*. They are essentially functions that execute on getting and setting a value, but look like regular properties to an external code. | ||||||
| O segundo tipo de propriedade é algo novo. É uma *propriedade de acesso*. Elas são, essencialmente, funções que executam ao obter e definir um valor, mas parecem propriedades normais para um código externo. | ||||||
|
|
||||||
| ## Getters and setters | ||||||
| ## Getters e setters | ||||||
|
|
||||||
| Accessor properties are represented by "getter" and "setter" methods. In an object literal they are denoted by `get` and `set`: | ||||||
| Propriedades de acesso são representadas por métodos "getter" e "setter". Num objeto literal, eles são indicados por `get` e `set`: | ||||||
|
|
||||||
| ```js | ||||||
| let obj = { | ||||||
| *!*get propName()*/!* { | ||||||
| // getter, the code executed on getting obj.propName | ||||||
| // getter, o código executado ao obter obj.propName | ||||||
| }, | ||||||
|
|
||||||
| *!*set propName(value)*/!* { | ||||||
| // setter, the code executed on setting obj.propName = value | ||||||
| // setter, o código executado ao definir obj.propName = value | ||||||
| } | ||||||
| }; | ||||||
| ``` | ||||||
|
|
||||||
| The getter works when `obj.propName` is read, the setter -- when it is assigned. | ||||||
| O getter funciona quando `obj.propName` é lido, o setter -- quando é atribuído. | ||||||
|
|
||||||
| For instance, we have a `user` object with `name` and `surname`: | ||||||
| Por exemplo, temos um objeto `user` com `name` e `surname`: | ||||||
|
|
||||||
| ```js | ||||||
| let user = { | ||||||
|
|
@@ -34,7 +34,7 @@ let user = { | |||||
| }; | ||||||
| ``` | ||||||
|
|
||||||
| Now we want to add a `fullName` property, that should be `"John Smith"`. Of course, we don't want to copy-paste existing information, so we can implement it as an accessor: | ||||||
| Agora queremos adicionar uma propriedade `fullName`, que deve ser `"John Smith"`. Claro, não queremos copiar e colar informações já existentes, então podemos implementá-la como um acessor: | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Terminologia inconsistente: a seção introduz o termo propriedade de acesso (linha 8) e usa-o nas linhas 56, 101 e 103, mas aqui e nas linhas 112, 137 e 188 aparece "acessor"/"acessores". Sugiro escolher um termo e usá-lo no artigo inteiro, para o leitor não achar que são conceitos diferentes. |
||||||
|
|
||||||
| ```js run | ||||||
| let user = { | ||||||
|
|
@@ -53,9 +53,9 @@ alert(user.fullName); // John Smith | |||||
| */!* | ||||||
| ``` | ||||||
|
|
||||||
| From the outside, an accessor property looks like a regular one. That's the idea of accessor properties. We don't *call* `user.fullName` as a function, we *read* it normally: the getter runs behind the scenes. | ||||||
| De fora, uma propriedade de acesso parece uma propriedade normal. Essa é a ideia das propriedades de acesso. Nós não *chamamos* `user.fullName` como uma função, nós a *lemos* normalmente: o getter roda nos bastidores. | ||||||
|
|
||||||
| As of now, `fullName` has only a getter. If we attempt to assign `user.fullName=`, there will be an error: | ||||||
| Por enquanto, `fullName` só tem um getter. Se tentarmos atribuir `user.fullName=`, vai haver um erro: | ||||||
|
|
||||||
| ```js run | ||||||
| let user = { | ||||||
|
|
@@ -65,11 +65,11 @@ let user = { | |||||
| }; | ||||||
|
|
||||||
| *!* | ||||||
| user.fullName = "Test"; // Error (property has only a getter) | ||||||
| user.fullName = "Test"; // Erro (a propriedade só tem um getter) | ||||||
| */!* | ||||||
| ``` | ||||||
|
|
||||||
| Let's fix it by adding a setter for `user.fullName`: | ||||||
| Vamos corrigir isso adicionando um setter para `user.fullName`: | ||||||
|
|
||||||
| ```js run | ||||||
| let user = { | ||||||
|
|
@@ -87,29 +87,29 @@ let user = { | |||||
| */!* | ||||||
| }; | ||||||
|
|
||||||
| // set fullName is executed with the given value. | ||||||
| // set fullName é executado com o valor dado. | ||||||
| user.fullName = "Alice Cooper"; | ||||||
|
|
||||||
| alert(user.name); // Alice | ||||||
| alert(user.surname); // Cooper | ||||||
| ``` | ||||||
|
|
||||||
| As the result, we have a "virtual" property `fullName`. It is readable and writable. | ||||||
| Como resultado, temos uma propriedade "virtual" `fullName`. Ela é legível e gravável. | ||||||
|
|
||||||
| ## Accessor descriptors | ||||||
| ## Descritores de acesso | ||||||
|
|
||||||
| Descriptors for accessor properties are different from those for data properties. | ||||||
| Os descritores de propriedades de acesso são diferentes dos de propriedades de dados. | ||||||
|
|
||||||
| For accessor properties, there is no `value` or `writable`, but instead there are `get` and `set` functions. | ||||||
| Para propriedades de acesso, não existe `value` ou `writable`, mas, em vez disso, existem as funções `get` e `set`. | ||||||
|
|
||||||
| That is, an accessor descriptor may have: | ||||||
| Ou seja, um descritor de acesso pode ter: | ||||||
|
|
||||||
| - **`get`** -- a function without arguments, that works when a property is read, | ||||||
| - **`set`** -- a function with one argument, that is called when the property is set, | ||||||
| - **`enumerable`** -- same as for data properties, | ||||||
| - **`configurable`** -- same as for data properties. | ||||||
| - **`get`** -- uma função sem argumentos, que funciona quando uma propriedade é lida, | ||||||
| - **`set`** -- uma função com um argumento, que é chamada quando a propriedade é definida, | ||||||
| - **`enumerable`** -- igual às propriedades de dados, | ||||||
| - **`configurable`** -- igual às propriedades de dados. | ||||||
|
|
||||||
| For instance, to create an accessor `fullName` with `defineProperty`, we can pass a descriptor with `get` and `set`: | ||||||
| Por exemplo, para criar um acessor `fullName` com `defineProperty`, podemos passar um descritor com `get` e `set`: | ||||||
|
|
||||||
| ```js run | ||||||
| let user = { | ||||||
|
|
@@ -134,13 +134,13 @@ alert(user.fullName); // John Smith | |||||
| for(let key in user) alert(key); // name, surname | ||||||
| ``` | ||||||
|
|
||||||
| Please note that a property can be either an accessor (has `get/set` methods) or a data property (has a `value`), not both. | ||||||
| Observe que uma propriedade pode ser um acessor (tem métodos `get/set`) ou uma propriedade de dados (tem um `value`), mas não as duas coisas. | ||||||
|
|
||||||
| If we try to supply both `get` and `value` in the same descriptor, there will be an error: | ||||||
| Se tentarmos fornecer `get` e `value` no mesmo descritor, vai haver um erro: | ||||||
|
|
||||||
| ```js run | ||||||
| *!* | ||||||
| // Error: Invalid property descriptor. | ||||||
| // Erro: Invalid property descriptor. | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Comentário mistura português e inglês. No artigo anterior (property-descriptors, linha 119) o padrão foi manter a mensagem original e traduzi-la entre parênteses. Sugestão para manter consistência:
Suggested change
|
||||||
| */!* | ||||||
| Object.defineProperty({}, 'prop', { | ||||||
| get() { | ||||||
|
|
@@ -151,11 +151,11 @@ Object.defineProperty({}, 'prop', { | |||||
| }); | ||||||
| ``` | ||||||
|
|
||||||
| ## Smarter getters/setters | ||||||
| ## Getters/setters mais espertos | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit: "espertos" soa coloquial para um título; "mais inteligentes" é a forma mais comum em material técnico.
Suggested change
|
||||||
|
|
||||||
| Getters/setters can be used as wrappers over "real" property values to gain more control over operations with them. | ||||||
| Getters/setters podem ser usados como invólucros sobre valores "reais" de propriedades, pra ganhar mais controle sobre as operações com eles. | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Registro informal: "pra" destoa do resto do artigo, que usa "para" em todos os outros lugares.
Suggested change
|
||||||
|
|
||||||
| For instance, if we want to forbid too short names for `user`, we can have a setter `name` and keep the value in a separate property `_name`: | ||||||
| Por exemplo, se quisermos proibir nomes muito curtos para `user`, podemos ter um setter `name` e manter o valor numa propriedade separada, `_name`: | ||||||
|
|
||||||
| ```js run | ||||||
| let user = { | ||||||
|
|
@@ -165,7 +165,7 @@ let user = { | |||||
|
|
||||||
| set name(value) { | ||||||
| if (value.length < 4) { | ||||||
| alert("Name is too short, need at least 4 characters"); | ||||||
| alert("O nome é muito curto, precisa ter pelo menos 4 caracteres"); | ||||||
| return; | ||||||
| } | ||||||
| this._name = value; | ||||||
|
|
@@ -175,19 +175,19 @@ let user = { | |||||
| user.name = "Pete"; | ||||||
| alert(user.name); // Pete | ||||||
|
|
||||||
| user.name = ""; // Name is too short... | ||||||
| user.name = ""; // O nome é muito curto... | ||||||
| ``` | ||||||
|
|
||||||
| So, the name is stored in `_name` property, and the access is done via getter and setter. | ||||||
| Então, o nome é armazenado na propriedade `_name`, e o acesso é feito via getter e setter. | ||||||
|
|
||||||
| Technically, external code is able to access the name directly by using `user._name`. But there is a widely known convention that properties starting with an underscore `"_"` are internal and should not be touched from outside the object. | ||||||
| Tecnicamente, código externo consegue acessar o nome diretamente usando `user._name`. Mas existe uma convenção amplamente conhecida de que propriedades começando com um sublinhado `"_"` são internas e não devem ser tocadas de fora do objeto. | ||||||
|
|
||||||
|
|
||||||
| ## Using for compatibility | ||||||
| ## Usando para compatibilidade | ||||||
|
|
||||||
| One of the great uses of accessors is that they allow to take control over a "regular" data property at any moment by replacing it with a getter and a setter and tweak its behavior. | ||||||
| Um dos grandes usos dos acessores é que eles permitem assumir o controle sobre uma propriedade de dados "normal" a qualquer momento, substituindo-a por um getter e um setter e ajustando seu comportamento. | ||||||
|
|
||||||
| Imagine we started implementing user objects using data properties `name` and `age`: | ||||||
| Imagine que começamos a implementar objetos de usuário usando as propriedades de dados `name` e `age`: | ||||||
|
|
||||||
| ```js | ||||||
| function User(name, age) { | ||||||
|
|
@@ -200,7 +200,7 @@ let john = new User("John", 25); | |||||
| alert( john.age ); // 25 | ||||||
| ``` | ||||||
|
|
||||||
| ...But sooner or later, things may change. Instead of `age` we may decide to store `birthday`, because it's more precise and convenient: | ||||||
| ...Mas, mais cedo ou mais tarde, as coisas podem mudar. Em vez de `age`, podemos decidir armazenar `birthday`, porque é mais preciso e conveniente: | ||||||
|
|
||||||
| ```js | ||||||
| function User(name, birthday) { | ||||||
|
|
@@ -211,21 +211,21 @@ function User(name, birthday) { | |||||
| let john = new User("John", new Date(1992, 6, 1)); | ||||||
| ``` | ||||||
|
|
||||||
| Now what to do with the old code that still uses `age` property? | ||||||
| Agora, o que fazer com o código antigo que ainda usa a propriedade `age`? | ||||||
|
|
||||||
| We can try to find all such places and fix them, but that takes time and can be hard to do if that code is used by many other people. And besides, `age` is a nice thing to have in `user`, right? | ||||||
| Podemos tentar encontrar todos esses lugares e corrigi-los, mas isso leva tempo e pode ser difícil se esse código for usado por muitas outras pessoas. E, além disso, `age` é algo bom de se ter em `user`, não é? | ||||||
|
|
||||||
| Let's keep it. | ||||||
| Vamos mantê-lo. | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. O pronome se refere à propriedade
Suggested change
|
||||||
|
|
||||||
| Adding a getter for `age` solves the problem: | ||||||
| Adicionar um getter para `age` resolve o problema: | ||||||
|
|
||||||
| ```js run no-beautify | ||||||
| function User(name, birthday) { | ||||||
| this.name = name; | ||||||
| this.birthday = birthday; | ||||||
|
|
||||||
| *!* | ||||||
| // age is calculated from the current date and birthday | ||||||
| // age é calculado a partir da data atual e do birthday | ||||||
| Object.defineProperty(this, "age", { | ||||||
| get() { | ||||||
| let todayYear = new Date().getFullYear(); | ||||||
|
|
@@ -237,8 +237,8 @@ function User(name, birthday) { | |||||
|
|
||||||
| let john = new User("John", new Date(1992, 6, 1)); | ||||||
|
|
||||||
| alert( john.birthday ); // birthday is available | ||||||
| alert( john.age ); // ...as well as the age | ||||||
| alert( john.birthday ); // birthday está disponível | ||||||
| alert( john.age ); // ...assim como age | ||||||
| ``` | ||||||
|
|
||||||
| Now the old code works too and we've got a nice additional property. | ||||||
| Agora o código antigo também funciona e ganhamos uma boa propriedade adicional. | ||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"Object literal" é um literal de objeto (a sintaxe
{...}); "objeto literal" lê como "um objeto que é literal". Sugestão: