From d0f7b5be76046950f7ff46a8ea323bb678dde27d Mon Sep 17 00:00:00 2001 From: Jonnathan Santos Date: Sun, 7 Apr 2024 17:09:02 -0300 Subject: [PATCH] sujeira --- .../07-optional-chaining/article.md | 204 +++++++----------- 1 file changed, 73 insertions(+), 131 deletions(-) diff --git a/1-js/04-object-basics/07-optional-chaining/article.md b/1-js/04-object-basics/07-optional-chaining/article.md index 4c6029423..e138ad0e2 100644 --- a/1-js/04-object-basics/07-optional-chaining/article.md +++ b/1-js/04-object-basics/07-optional-chaining/article.md @@ -1,233 +1,175 @@ -# Optional chaining '?.' +# Encadeamento Opcional '?.' [recent browser="new"] -The optional chaining `?.` is a safe way to access nested object properties, even if an intermediate property doesn't exist. +O encadeamento opcional `?.` é um jeito à prova de erro de acessar propriedades encapsuladas dentro de um objeto, mesmo se tal propriedade não existir. -## The "non-existing property" problem +## O problema -If you've just started to read the tutorial and learn JavaScript, maybe the problem hasn't touched you yet, but it's quite common. +Se você acabou de começar a ler o tutorial e aprender JavaScript, talvez o problema ainda não tenha afetado você, mas é um problema bem comum. -As an example, let's say we have `user` objects that hold the information about our users. - -Most of our users have addresses in `user.address` property, with the street `user.address.street`, but some did not provide them. - -In such case, when we attempt to get `user.address.street`, and the user happens to be without an address, we get an error: +Por exemplo, alguns de nossos usuários possuem um endereço, mas alguns deles ainda não o especificaram. Portanto nós não podemos ler `user.address.street` de forma segura: ```js run -let user = {}; // a user without "address" property +let user = {}; // o usuário não possui um endereço -alert(user.address.street); // Error! +alert(user.address.street); // Erro! ``` -That's the expected result. JavaScript works like this. As `user.address` is `undefined`, an attempt to get `user.address.street` fails with an error. - -In many practical cases we'd prefer to get `undefined` instead of an error here (meaning "no street"). - -...and another example. In Web development, we can get an object that corresponds to a web page element using a special method call, such as `document.querySelector('.elem')`, and it returns `null` when there's no such element. +Ou, no desenvolvimento web, nós gostaríamos de obter uma informação sobre um elemento da página, mas pode ser que ele não exista: ```js run -// document.querySelector('.elem') is null if there's no element -let html = document.querySelector('.elem').innerHTML; // error if it's null -``` - -Once again, if the element doesn't exist, we'll get an error accessing `.innerHTML` property of `null`. And in some cases, when the absence of the element is normal, we'd like to avoid the error and just accept `html = null` as the result. - -How can we do this? - -The obvious solution would be to check the value using `if` or the conditional operator `?`, before accessing its property, like this: - -```js -let user = {}; - -alert(user.address ? user.address.street : undefined); -``` - -It works, there's no error... But it's quite inelegant. As you can see, the `"user.address"` appears twice in the code. - -Here's how the same would look for `document.querySelector`: - -```js run -let html = document.querySelector('.elem') ? document.querySelector('.elem').innerHTML : null; -``` - -We can see that the element search `document.querySelector('.elem')` is actually called twice here. Not good. - -For more deeply nested properties, it becomes even uglier, as more repetitions are required. - -E.g. let's get `user.address.street.name` in a similar fashion. - -```js -let user = {}; // user has no address - -alert(user.address ? user.address.street ? user.address.street.name : null : null); +// Erro se o resultado de querySelector(...) é null +let html = document.querySelector('.my-element').innerHTML; ``` -That's just awful, one may even have problems understanding such code. - -There's a little better way to write it, using the `&&` operator: +Antes que `?.` aparecesse na linguagem, o operador `&&` era usado para dar um jeito nisso. +Por exemplo: ```js run -let user = {}; // user has no address +let user = {}; // o usuário ainda não possui um endereço -alert( user.address && user.address.street && user.address.street.name ); // undefined (no error) +alert( user && user.address && user.address.street ); // undefined (sem erro) ``` -AND'ing the whole path to the property ensures that all components exist (if not, the evaluation stops), but also isn't ideal. - -As you can see, property names are still duplicated in the code. E.g. in the code above, `user.address` appears three times. - -That's why the optional chaining `?.` was added to the language. To solve this problem once and for all! +utilizar o AND por todo o caminho garante que todos os componentes existam, porém é trabalhoso escrever tudo isso. -## Optional chaining +## Encadeamento opcional -The optional chaining `?.` stops the evaluation if the value before `?.` is `undefined` or `null` and returns `undefined`. +O encadeamento opcional `?.` acaba com a avaliação e retorna `undefined` se a parte anterior de `?.` é `undefined` ou `null`. -**Further in this article, for brevity, we'll be saying that something "exists" if it's not `null` and not `undefined`.** +Ao longo deste artigo, por uma questão de tempo, diremos que algo "existe" se não é `null` e não é `undefined`. -In other words, `value?.prop`: -- works as `value.prop`, if `value` exists, -- otherwise (when `value` is `undefined/null`) it returns `undefined`. -Here's the safe way to access `user.address.street` using `?.`: +Aqui está a forma segura de acessar `user.address.street`: ```js run -let user = {}; // user has no address +let user = {}; // o usuário não possui um endereço -alert( user?.address?.street ); // undefined (no error) -``` - -The code is short and clean, there's no duplication at all. - -Here's an example with `document.querySelector`: - -```js run -let html = document.querySelector('.elem')?.innerHTML; // will be undefined, if there's no element +alert( user?.address?.street ); // undefined (sem erro) ``` Reading the address with `user?.address` works even if `user` object doesn't exist: +Ler o endereço com `user?.address` funciona mesmo se o objeto `user` não existir: ```js run let user = null; alert( user?.address ); // undefined + alert( user?.address.street ); // undefined +alert( user?.address.street.anything ); // undefined ``` -Please note: the `?.` syntax makes optional the value before it, but not any further. +Observação: A sintaxe `?.` funciona exatamente onde ela é colocada, não adiante. -E.g. in `user?.address.street.name` the `?.` allows `user` to safely be `null/undefined` (and returns `undefined` in that case), but that's only for `user`. Further properties are accessed in a regular way. If we want some of them to be optional, then we'll need to replace more `.` with `?.`. +Nas últimas duas linhas a avaliação para imediatamente após `user?.`, não chegando a acessar as seguintes propriedades. Mas se `user` de fato existir, então as propriedades seguintes, como `user.address` devem existir. -```warn header="Don't overuse the optional chaining" -We should use `?.` only where it's ok that something doesn't exist. +```warn header="Não abuse do encadeamento opcional" +Nós devemos usar `?.` apenas onde é possível ter algo que não existe. -For example, if according to our code logic `user` object must exist, but `address` is optional, then we should write `user.address?.street`, but not `user?.address?.street`. +Por exemplo, se de acordo com a nossa lógica de código o objeto `user` existe, porém `address` é opcional, então seria melhor utilizar `user.address?.street`. -Then, if `user` happens to be undefined, we'll see a programming error about it and fix it. Otherwise, if we overuse `?.`, coding errors can be silenced where not appropriate, and become more difficult to debug. +Portanto, se `user` estiver indefinido devido a um erro, saberemos e o corrigiremos. Caso contrário, os erros poderão ser silenciados onde não forem apropriados, e assim se tornando mais difíceis de debugar. ``` -````warn header="The variable before `?.` must be declared" -If there's no variable `user` at all, then `user?.anything` triggers an error: +```warn header="A variável anterior a `?.` deve existir" +Se não existe a variável `user`, então `user?.anything` causa um erro: ```js run -// ReferenceError: user is not defined +// ReferenceError: user não é definido user?.address; ``` -The variable must be declared (e.g. `let/const/var user` or as a function parameter). The optional chaining works only for declared variables. -```` +O encadeamento opcional apenas testa por `null/undefined`, não interfere em nenhuma outra mecânica da linguagem. -## Short-circuiting +## Curto-circuito -As it was said before, the `?.` immediately stops ("short-circuits") the evaluation if the left part doesn't exist. +Como dito anteriormente, o `?.` interrompe imediatamente ("curto-circuito") a avaliação se a parte esquerda não existir. -So, if there are any further function calls or operations to the right of `?.`, they won't be made. - -For instance: +Então, se tiver qualquer outra chamada de função ou efeito colateral a seguir, serão ignorados: ```js run let user = null; let x = 0; -user?.sayHi(x++); // no "user", so the execution doesn't reach sayHi call and x++ +user?.sayHi(x++); // nada acontece -alert(x); // 0, value not incremented +alert(x); // 0, valor não incrementado ``` -## Other variants: ?.(), ?.[] +## Outros casos: ?.(), ?.[] -The optional chaining `?.` is not an operator, but a special syntax construct, that also works with functions and square brackets. +O encadeamento opcional `?.` não é um operador, mas uma construção especial de sintaxe, que também funciona com funções e colchetes. -For example, `?.()` is used to call a function that may not exist. +Por exemplo, `?.()` é usado para chamar uma função que possa não existir. -In the code below, some of our users have `admin` method, and some don't: +No código a seguir, alguns usuários possuem o método `admin`, e alguns não: ```js run -let userAdmin = { +let user1 = { admin() { - alert("I am admin"); + alert("Eu sou admin"); } -}; +} -let userGuest = {}; +let user2 = {}; *!* -userAdmin.admin?.(); // I am admin -*/!* - -*!* -userGuest.admin?.(); // nothing happens (no such method) +user1.admin?.(); // Eu sou admin +user2.admin?.(); */!* ``` -Here, in both lines we first use the dot (`userAdmin.admin`) to get `admin` property, because we assume that the `user` object exists, so it's safe read from it. +Aqui, nas duas linhas, primeiro usamos o ponto `.` para acessar a propriedade `admin`, porque o objeto usuário deve existir, portanto é uma leitura segura. -Then `?.()` checks the left part: if the `admin` function exists, then it runs (that's so for `userAdmin`). Otherwise (for `userGuest`) the evaluation stops without errors. +Então `?.()` verifica a parte esquerda: se o usuário existe, então é executado (no caso `user1`). Caso contrário (no caso `user2`) a avaliação é interrompida sem erros. -The `?.[]` syntax also works, if we'd like to use brackets `[]` to access properties instead of dot `.`. Similar to previous cases, it allows to safely read a property from an object that may not exist. +A sintaxe `?.[]` também funciona, se nós queremos utilizar colchetes `[]` para acessar propriedades ao invés do ponto `.`. Similarmente aos casos anteriores, nos permite acessar de forma segura a propriedade de um objeto que possa não existir. ```js run -let key = "firstName"; - let user1 = { firstName: "John" }; -let user2 = null; +let user2 = null; // Imagine, nós não pudemos autorizar o usuário + +let key = "firstName"; alert( user1?.[key] ); // John alert( user2?.[key] ); // undefined + +alert( user1?.[key]?.something?.not?.existing); // undefined ``` -Also we can use `?.` with `delete`: +Também podemos usar `?.` com `delete`: ```js run -delete user?.name; // delete user.name if user exists +delete user?.name; // deleta user.name se o usuário existe ``` -````warn header="We can use `?.` for safe reading and deleting, but not writing" -The optional chaining `?.` has no use on the left side of an assignment. +```warn header="Nós podemos usar `?.` para ler e deletar de forma segura, mas não para escrever" +O encadeamento opcional `?.` não possui utilidade ao lado esquerdo de uma atribuição: -For example: ```js run -let user = null; +// A idéia do código a seguir é a de escrever user.name, se o usuário existir -user?.name = "John"; // Error, doesn't work -// because it evaluates to: undefined = "John" +user?.name = "John"; // Erro, não funciona +// porque é avaliado para undefined = "John" ``` -```` +## Resumo -## Summary +A sintaxe `?.` possui 3 formas: -The optional chaining `?.` syntax has three forms: +1. `obj?.prop` -- retorna `obj.prop` se `obj` existe, caso contrário `undefined`. +2. `obj?.[prop]` -- retorna `obj[prop]` if `obj` existe, caso contrário `undefined`. +3. `obj?.method()` -- chama `obj.method()` if `obj` existe, caso contrário retorna `undefined`. -1. `obj?.prop` -- returns `obj.prop` if `obj` exists, otherwise `undefined`. -2. `obj?.[prop]` -- returns `obj[prop]` if `obj` exists, otherwise `undefined`. -3. `obj.method?.()` -- calls `obj.method()` if `obj.method` exists, otherwise returns `undefined`. +Como podemos ver, todas as formas são bem diretas e simples de usar. O `?.` verifica se a parte esquerda é `null/undefined` e permite que a avaliação prossiga caso contrário. -As we can see, all of them are straightforward and simple to use. The `?.` checks the left part for `null/undefined` and allows the evaluation to proceed if it's not so. +Uma cadeia de `?.` permite um acesso seguro a propriedades encapsuladas dentro de um objeto. -A chain of `?.` allows to safely access nested properties. +Mesmo assim, devemos usar `?.` com cuidado, apenas se é possível que a parte esquerda não exista. -Still, we should apply `?.` carefully, only where it's acceptable, according to our code logic, that the left part doesn't exist. So that it won't hide programming errors from us, if they occur. +Para que não tenhamos erros ocultados, caso aconteçam. \ No newline at end of file