6 recursos JavaScript que você deve conhecer
Publicados: 2020-09-24Há pouco mais de um ano falamos sobre os 5 “novos” recursos JavaScript que você deve conhecer para desenvolver confortavelmente em Gutenberg. Lá aprendemos o que são desestruturação de objetos e arrays, como criar funções de seta, o que são os operadores spread e rest, e assim por diante. Para sua sorte, o JavaScript ainda tem muitos recursos que, quando você estiver familiarizado com eles, ajudarão você a escrever um código mais inteligível e sucinto.
Hoje vou mostrar seis recursos JavaScript muito legais. Operadores, escopo de variáveis, promessas, funções assíncronas... você está pronto para aprender tudo isso?
#1 Encadeamento opcional em JavaScript com o operador ?.
O operador de encadeamento opcional permite acesso simplificado aos atributos de um objeto quando há uma chance de que um seja undefined ou null . Por exemplo, suponha que você tenha um objeto como o seguinte:
const toni = { name: 'Antonio', details: { age: 35, }, }; Para acessar a age de toni , primeiro você deve acessar o atributo details e depois age :
function getAge( person ) { return person.details.age; } O problema que temos na função anterior, e tenho certeza que não é novidade para você, é que as propriedades que esperamos que a person tenha nem sempre estão lá. Ou seja, se person ou person.details for undefined , a função acima acionará um erro de tipo:
getAge( toni ); // 35 getAge( {} ); // Uncaught TypeError: person.details is undefinedNormalmente, superamos esse problema adicionando algumas proteções:
function getAge( person ) { if ( ! person ) { return; } if ( ! person.details ) { return; } return person.details.age; } getAge( toni ); // 35 getAge( {} ); // undefined que claramente o corrige. Infelizmente, a função resultante é mais complexa e tem muito código barulhento que desvia nossa atenção das coisas que realmente importam. Para voltar aos trilhos e corrigir a solução de maneira mais simples, basta usar o operador de encadeamento opcional ?. :
function getAge( person ) { return person?.details?.age; } getAge( toni ); // 35 getAge( {} ); // undefined Essencialmente, este operador nos permite acessar cada propriedade desde que não seja undefined ou null . Assim que detecta que tentamos acessar uma propriedade de um objeto inexistente, ele retorna undefined .
# 2 Operador de Coalescência Nulo ( ?? )
Em JavaScript é muito fácil definir um valor padrão para uma variável usando este operador: || , certo? Errado! Todos nós já fizemos isso, mas pode resultar em efeitos colaterais inesperados se você não tomar cuidado…
Por exemplo, suponha que temos um seletor em nossa loja Redux que nos permite recuperar um valor definido pelo usuário. Se o usuário ainda não especificou um valor (ou seja, o valor é undefined ), retornamos um valor padrão usando || :
function getValue( state ) { return state.value || 5; }Agora, vamos ver alguns exemplos do que obteríamos com a função anterior depois que o usuário definir um valor ou outro:
// No setValue( x )... getValue(); // 5 setValue( 2 ); getValue(); // 2 setValue( 1 ); getValue(); // 1 setValue( 0 ); getValue(); // 5 Opa! Tudo funcionou bem até chegarmos ao último caso! Aparentemente, se o usuário definir o valor como 0 , o resultado da função se torna 5 . Por quê? Bem, a lógica é bastante óbvia: x||y retorna y se, e somente se, x for um valor “falso”. Isso geralmente funciona bem, pois undefined é um valor falsey. Mas também são false ou 0 , por exemplo.
Na realidade, só queríamos definir um valor default quando não há nenhum. Assim, podemos adicionar um safe guard para verificar se há um valor ou não:
function getValue( state ) { if ( undefined === state.value ) return 5; return state.value; }e podemos até escrevê-lo usando o operador ternário se quisermos:
function getValue( state ) { return undefined === state.value ? 5 : state.value; } mas, mais uma vez, ambas as soluções complicam desnecessariamente o código. Para atribuir um valor padrão a uma variável, devemos usar o operador de coalescência nulo ?? , que retorna a parte direita se, e somente se, a parte esquerda for null ou undefined :
function getValue( state ) { return state.value ?? 5; }e, surpresa-surpresa!, o resultado é exatamente o que queríamos:
// No setValue( x )... getValue(); // 5 setValue( 2 ); getValue(); // 2 setValue( 1 ); getValue(); // 1 setValue( 0 ); getValue(); // 0Ah, e a propósito, você pode usar esse operador combinado com uma atribuição. Por exemplo, isso:
value = value ?? 5;é equivalente a isso:
value ??= 5;#3 Promessas e funções assíncronas
As promessas são um mecanismo implementado em JavaScript que nos permite simplificar nosso código-fonte ao trabalhar com operações assíncronas, ou seja, operações cujos resultados não estão disponíveis imediatamente. Por exemplo, se queremos recuperar dados do nosso servidor, é claro que a resposta não será instantânea, pois temos que esperar que o servidor receba a solicitação, processe-a e nos envie a resposta de volta.
Em versões e bibliotecas JavaScript mais antigas (por exemplo, jQuery), costumávamos implementar isso com retornos de chamada. A ideia era bem simples: junto com a requisição em si, definir a função (o callback) que deve ser chamada assim que a resposta estiver disponível. Dessa forma, quando a operação assíncrona (ou seja, recuperar dados do servidor) for concluída, a biblioteca chamará a função e nossa lógica será retomada:
jQuery.ajax( { url: 'https://server.com/wp-json/wp/users/1', success: ( user ) => { console.log( user ); }, } );Se estivermos acionando apenas uma solicitação única e isolada, essa solução é bastante elegante e conveniente. Mas, assim que precisamos realizar mais solicitações, as coisas ficam sujas rapidamente. Por exemplo, se quisermos solicitar dois usuários diferentes, teríamos que aninhar retornos de chamada:

jQuery.ajax( { url: 'https://server.com/wp-json/wp/v2/users/1', success: ( user1 ) => { jQuery.ajax( { url: 'https://server.com/wp-json/wp/v2/users/2', success: ( user2 ) => { console.log( user1, user2 ); }, } ); }, } );As promessas são a solução para esse problema: se a obtenção de um determinado resultado não for imediata (como, por exemplo, quando recuperamos algo de um servidor), podemos retornar uma promessa JavaScript imediatamente. Este objeto é um wrapper do valor real e significa a “promessa” de que esse valor estará disponível em algum momento no futuro.
Por exemplo, se reescrevêssemos nosso primeiro snippet usando promessas, ficaria assim:
const promise = wp.apiFetch( { url: 'https://server.com/wp-json/wp/v2/users/1', } ); promise.then( ( user ) => console.log( user ) ); Como você pode ver, wp.apiFetch tem que buscar o usuário 1 do servidor, mas dá um resultado imediatamente. O resultado, no entanto, não é o próprio usuário, mas uma promessa que será resolvida para o usuário assim que as solicitações forem concluídas. Portanto, tudo o que precisamos fazer é escrever um retorno de chamada que processará a resposta da promessa quando ela for resolvida.
Você agora pode estar pensando que isso não é tão difícil do que tínhamos antes, certo? Afinal, ainda estamos usando callbacks… mas você pode ver como isso é útil quando começamos a combinar várias solicitações:
const promise1 = wp.apiFetch( { url: 'https://server.com/wp-json/wp/v2/users/1', } ); const promise2 = wp.apiFetch( { url: 'https://server.com/wp-json/wp/v2/users/2', } ); Promise.all( [ promise1, promise2 ] ).then( ( [ user1, user2 ] ) => console.log( user1, user2 ); ); Usando promessas, conseguimos lançar duas solicitações paralelas para recuperar os usuários 1 e 2 e usar Promise.all para esperar que ambas as promessas fossem resolvidas. Nenhum código de espaguete com retornos de chamada aninhados envolvidos.
Bem, a grande coisa sobre promessas ainda está por vir. Podemos usar um pouco de açúcar sintático para trabalhar com promessas de JavaScript e escrever código assíncrono que pareça, bem, síncrono. Tudo o que você precisa fazer é definir uma função assíncrona usando a palavra-chave async e de repente as coisas ficam muito, muito mais fáceis:
async function logTwoUsers( id1, id2 ) { const user1 = await wp.apiFetch( { url: '…' + id1 } ); const user2 = await wp.apiFetch( { url: '…' + id2 } ); console.log( user1, user2 ); } Sempre que você chamar uma operação assíncrona em uma função assíncrona, poderá aguardar seu resultado usando a palavra-chave await . A única coisa que você deve ter em mente é que, ao definir uma função async , seu resultado sempre será uma promessa:
async function getNumberFive() { return 5; } const p = getNumberFive(); // a promise p.then( console.log ); // prints "5" #4 Escopo variável ao usar let e const
Como você provavelmente já sabe, agora você pode declarar variáveis usando as palavras-chave let e const . O primeiro define uma variável e o último define uma constante:
let x = 1; console.log( x ); // 1 x = 2; console.log( x ); // 2 const y = 1; console.log( y ); // 1 y = 2; // Uncaught TypeError: invalid assignment to const 'y' console.log( y ); // 1 Você pode ficar tentado a pensar que let e var são a mesma coisa, pois ambas as palavras-chave nos permitem declarar uma variável não constante. Mas há uma diferença substancial entre eles: seu escopo. Com let e const , o escopo da variável é o bloco onde ela está definida. Em var , é toda a função.
function fn() { if ( true ) { var x = 1; let y = 2; const z = 3; }//end if console.log( x ); // 1 console.log( y ); // Uncaught ReferenceError: y is not defined console.log( z ); // Uncaught ReferenceError: z is not defined } # 5 Transformação de dados ao usar JSON.parse
A função JSON.parse analisa uma string JSON e cria um objeto JavaScript. Por exemplo:
const x = JSON.parse( '{"x":1,"a":[1,2,3]}' ); // Object { x: 1, a: [ 1, 2, 3 ] } O que a maioria das pessoas não sabe é que ele suporta um segundo argumento chamado reviver . Este parâmetro é uma função que será executada para cada elemento que está sendo analisado, permitindo que você manipule o valor como quiser. Por exemplo, imagine uma string JSON como a seguinte:
const json = '{"name":"David","birthday":"1985-12-01T10:00:00.000Z"}'; Se usarmos JSON.parse como está, ele gerará um objeto com dois atributos de string: name e birthday . Mas se fornecermos uma função JSON.parse reviver podemos garantir que birthday seja analisado como Date :
const user = JSON.parse( json, ( key, value ) => 'birthday' === key ? new Date( value ) : value ) # 6 Separador Numérico no Código Fonte Usando o Caractere Undersrcore ( _ )
Nossa última dica de hoje é o separador numérico. Existe uma proposta (atualmente em estágio 4) que possibilita escrever números de uma forma que facilite a compreensão do ser humano. Por exemplo, você pode realmente dizer quão grandes são os números a seguir?
10000000000 2189719.25 Se pudéssemos usar o separador de milhares, seria muito mais fácil de interpretar! E é exatamente isso que podemos fazer usando o sublinhado _ :
10_000_000_000 2_189_719.25Resumo
É possível escrever um código JavaScript melhor se você se acostumar com todas as novas ferramentas e recursos incluídos no JavaScript. Hoje vimos vários exemplos do que é possível com esta linguagem de programação. Espero que você tenha aprendido algo novo e se gostou, não se esqueça de compartilhar com seus colegas. Vejo você em breve!
Imagem em destaque por Sam Dan Truong no Unsplash.
