No artigo de hoje vou apresentar a você 15 dicas muito boas da linguagem JavaScript, geralmente atalhos de codificação, mas além disso também recursos da linguagem que poucas pessoas conhecem e algumas ‘manhas’ que podem ser muito úteis para programadores JS em geral mas principalmente aos meus alunos do curso de Node.js e MongoDB.
Atenção: nem todas dicas, especialmente os atalhos de código, vão agradar a todo mundo. A intenção é lhe mostrar possibilidades interessantes, mas saber quando é o melhor momento para usar cada uma delas fica à critério do programador (levando em conta a legibilidade do código, por exemplo).
A lista de dicas é composta por:
- Testes de Null ou Undefined
- Atribuição de Arrays
- Operador Ternário
- Declarando variáveis
- Auto-atribuição de Variáveis
- Uso de RegExp
- Atalho do charAt()
- Exponenciais base-10
- ES6 Template Literals
- ES6: Arrow Functions
- ES6: Argument Destructuring
- ES6: Key-Value Names
- ES6: Map
- ES6: Filter
- ES6: Reduce
#1 – Testes de Null ou Undefined
Uma das coisas que logo aprendemos em JavaScript é que nem tudo é o que parece ser e que existem diversas maneiras de uma variável lhe causar problemas em uma linguagem dinâmica como essa. Um teste muito comum de ser feito é para verificar se uma variável está null ou undefined, ou ainda ‘vazia’, como abaixo:
1 2 3 4 |
if (variavel1 !== null || variavel1 !== undefined || variavel1 !== '') let variavel2 = variavel1; |
Um jeito bem mais simples de fazer o mesmo teste seria:
1 2 3 |
let variavel2 = variavel1 || ''; |
Se não acredita, pode testar!
#2 – Atribuição de Arrays
Então você tem de criar um objeto Array e depois popular ele com seus elementos, certo? Provavelmente seu código irá se parecer com isso:
1 2 3 4 5 6 |
let a = new Array(); a[0] = "s1"; a[1] = "s2"; a[2] = "s3"; |
Que tal fazer a mesma coisa em apenas uma linha?
1 2 3 |
let a = ["s1", "s2", "s3"]; |
Bacana, hein!
#3 – Operador Ternário
O famoso ‘if/else em uma linha’, o operador ternário já é um velho conhecido de diversos programadores de linguagens C-like como Java e C#. Pois é, ele existe em JS também e pode facilmente transformar blocos de código como esse:
1 2 3 4 5 6 7 8 9 |
let big; if (x > 10) { big = true; } else { big = false; } |
Nisso aqui:
1 2 3 |
let big = x > 10 ? true : false; |
Entendeu agora porque muita gente chama o ternário de ‘if/else em uma linha’?
Mas será que funciona com chamadas de funções também? Se eu tenho duas functions diferentes e quero chamar uma no caso do if ser verdadeiro e outra no caso do if ser falso, corriqueiramente você faria algo assim:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
function x() {console.log('x')}; function y() {console.log('y')}; let z = 3; if (z == 3) { x(); } else { y(); } |
Mas…segure-se na cadeira, talvez você não goste do que vai ver…você pode fazer a mesma chamada de função usando o ternário:
1 2 3 4 5 6 7 |
function x() {console.log('x')}; function y() {console.log('y')}; let z = 3; (z==3?x:y)(); // Atalho! |
Wow! Aqui no RS temos uma expressão para quando ficamos espantados com algo que é: “me caiu os butiá do bolso“.
Vale uma menção honrosa também aos ifs que testam se uma variável é verdadeira, onde alguns programadores ainda fazem assim:
1 2 3 |
if (likeJs === true) |
Quando podem fazer assim:
1 2 3 |
if (likeJs) |
Ou a versão negada:
1 2 3 4 5 6 |
let c; if ( c!= true ) { // faz alguma coisa... } |
Que pode facilmente ser resumida com:
1 2 3 4 5 6 |
let c; if ( !c ) { // faz alguma coisa... } |
#4 – Declarando Variáveis
Sim, mesmo a declaração de variáveis possui os seus melindres. Embora isso não seja exatamente um segredo, ainda se vê muito programador fazendo declarações como essa:
1 2 3 4 5 |
let x; let y; let z = 3; |
Quando podia estar fazendo assim:
1 2 3 |
let x, y, z=3; |
#5 – Auto-Atribuição de Variáveis
Também outra dica bem comum, ao menos em meus cursos, para, ao invés de auto atribuir valores em variáveis numéricas desta forma:
1 2 3 4 5 |
x=x+1; menor = menor - 1; y=y*10; |
Os programadores usem versões mais enxutas, como essas:
1 2 3 4 5 |
x++; menor--; y*=10; |
E se você não conseguiu entender o terceiro exemplo (*=) considere que x=10 e y=5 para as seguintes expressões, verificando o resultado manualmente no seu caderno:
1 2 3 4 5 6 7 |
x += y //resulta x=15 x -= y //resulta x=5 x *= y //resulta x=50 x /= y //resulta x=2 x %= y //resulta x=0 |
#6 – Uso de RegExp
Expressões Regulares já são, por si só, uma baita ferramenta para criar códigos mais elegantes e poderosos quando o assunto é análise e validações textual, além de extração de dados no caso de alguns tipos de webcrawlers.
No entanto, em JS muitas vezes os programadores usam o objeto RegExp desta maneira:
1 2 3 4 5 |
var re = new RegExp("d+(.)+d+","igm"), result = re.exec("padding 01234 text text 56789 padding"); console.log(result); //"01234 text text 56789" |
Quando poderiam estar usando desta maneira:
1 2 3 4 |
var result = /d+(.)+d+/igm.exec("padding 01234 text text 56789 padding"); console.log(result); //"01234 text text 56789" |
Eu sei, não é o código mais legível do mundo, mas em situações em que o tamanho do arquivo JS importa, essa é uma excelente dica de minificação de código.
Não sabe fazer Regex? Aprenda com esta minha mini-aula:
#7 – Atalho do charAt()
Então você quer pegar um caracter apenas de uma String, em uma posição específica, certo? Aposto que a primeira coisa que lhe vem em mente é usar a função charAt, como abaixo:
1 2 3 |
"string".charAt(0); |
Mas veja só, você consegue o mesmo resultado lembrando-se daquela analogia da String ser um Array de chars:
1 2 3 |
"string"[0]; // Returns 's' |
#8 – Exponenciais Base-10
Esta é apenas uma notação mais enxuta para números exponenciais na Base-10 ou os famosos ‘números cheios de zeros’. Para quem é mais chegado em matemática não vai se surpreender muito ao ver um desses, mas um número 10.000 pode ser facilmente substituído em JS por 1e4, ou seja, 1 seguido de 4 zeros, como abaixo:
1 2 3 |
for (let i = 0; i < 1e4; i++) { |
As dicas a seguir são todas da versão 6 do padrão JavaScript, chamada ECMAScript. Essa é a versão de JavaScript que mais utilizo no meu curso de Node.js e MongoDB, e além de mostrá-las na prática durante o curso, registro aqui para quem ainda não é aluno.
#9 – ES6: Template Literals
Essa funcionalidade semântica é exclusiva da versão ECMAScript 6 ou superior e simplifica bastante a leitura de concatenação de strings em conjunto de variáveis. Por exemplo, a concatenação abaixo:
1 2 3 |
const stringao = “Meu número é “ + number + “, ok?” |
Essa até é simples e provavelmente você já fez concatenações piores. A partir do ES6, podemos fazer esta concatenação usando template literals:
1 2 3 |
const stringao = `Meu número é ${number}, ok?` |
Note que ${} delimitam que dentro vai uma variável que deve ser concatenada, sendo number a mesma, ok? Note também o uso de crase na string ao invés das tradicionais aspas.
#10 – ES6: Arrow Functions
Arrow Functions são formas abreviadas de declarar funções. Sim, mais formas de fazer a mesma coisa que funciona desde a primeira versão do JavaScript. Por exemplo, abaixo uma função de soma:
1 2 3 4 5 |
function somar(n1,n2){ return n1 + n2; } |
Também podemos declarar esta function desta forma:
1 2 3 4 5 |
const somar = function(n1,n2){ return n1+n2; } |
Mas com Arrow Functions podemos levar essa declaração a outro patamar como abaixo:
1 2 3 |
const somar = (n1,n2) => n1+n2; |
E se for usar anonymous functions, fica mais fácil ainda, como nos callbacks do Node! Note que o return ficou implícito nessa declaração também, pois ela tem apenas uma linha, então é óbvio o que ela deve retornar.
#11 – ES6: Argument Destructuring
Essa dica é para aquelas functions que são cheias de parâmetros e você decidiu substituir todos por um objeto. Ou então para aquelas functions que realmente exigem um objeto de configuração por parâmetro.
Até aí nenhum problema, afinal quem nunca passou por isso? O problema é ter que ficar acessando o objeto que foi passado por parâmetro seguido de cada propriedade que queremos ler, certo? Tipo isso:
1 2 3 4 5 6 7 8 9 |
function inicializar(config){ const s = config.s; const t = config.t; return s + t;// ou config.s + config.t } inicializar({s: "1", t: "2"}); |
O recurso de argument destructuring (desestruturação de argumentos) serve justamente pra simplificar isso e ao mesmo tempo ajudar na legibilidade de código, substituindo a declaração anterior por essa:
1 2 3 4 5 6 7 |
function inicializar({s, t}){ return s + t; } inicializar({s: , t: "2"}); |
E para completar, ainda podemos deixar valores default em propriedades do nosso objeto-parâmetro:
1 2 3 4 5 6 7 |
function inicializar({s = "def1", t = "def2"}){ return s + t; } inicializar({s: "1"}); |
Dessa forma, o valor de s será “1”, mas o de t será o default para essa propriedade que será “def2”.
#12 – ES6: Key-Value Names
Um recurso muito viciante é a forma abreviada de se atribuir propriedades para objetos. Imagine que você tem um objeto person que tem uma propriedade name que vai ser atribuída através de uma variável name. Isso ficaria assim:
1 2 3 4 5 |
const name = "Luiz" const person = { name: name } // { name: "Luiz" } |
Enquanto que em ES6 você pode fazer assim:
1 2 3 4 5 |
const name = "Luiz" const person = { name } // { name: "Luiz" } |
Ou seja, se sua variável possui o mesmo nome da propriedade, não precisa chamar a mesma, apenas passe a variável. O mesmo vale para múltiplas propriedades:
1 2 3 4 5 6 |
const name = "Luiz" const programmingAbility = "POG" const person = { name, programmingAbility } // { name: "Luiz", programmingAbility: "POG" } |
#13 – ES6: Map
Esse operador é muito bacana, me lembra um dos principais motivos pelos quais eu usava JQuery em meus projetos web e desde o ES6 é um recurso nativo do JavaScript!
Para os exemplos de código, considere o array de objetos a seguir:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
const animais = [ { "nome": "gato", "tamanho": "pequeno", "peso": 5 }, { "nome": "cachorro", "tamanho": "pequeno", "peso": 10 }, { "nome": "leão", "tamanho": "médio", "peso": 150 }, { "nome": "elefante", "tamanho": "grande", "peso": 5000 } ] |
Imagine agora que queremos pegar apenas os nomes dos animais para, por exemplo, adicionar em outro array. Normalmente faríamos isso:
1 2 3 4 5 6 7 |
let nomes_animais = []; for (let i = 0; i < animais.length; i++) { nomes_animais.push(animais[i].nome); } |
Mas com o Map, podemos fazer assim:
1 2 3 4 5 |
let nomes_animais = animais.map((animal, index, animais) => { return animal.nome; }) |
Note que o map espera uma function por parâmetro com três argumentos: o primeiro é o objeto atual (como em um foreach), o segundo é o índice da iteração atual e o terceiro é o array inteiro. Obviamente esta função será chamada uma vez para cada objeto no array animais.
#14 – ES6: Filter
E se queremos iterar através do mesmo array de objetos animais da dica anterior, mas desta vez retornando apenas aqueles cujo tamanho seja “pequeno”?
Como faríamos isso com JS regular?
1 2 3 4 5 6 7 8 9 |
let animais_pequenos = []; for (let i = 0; i < animais.length; i ++) { if (animais[i].tamanho === "pequeno") { animais_pequenos.push(animais[i]) } } |
No entanto, usando o operador filter, podemos fazê-lo de uma maneira bem menos verbosa e mais clara:
1 2 3 4 5 |
let animais_pequenos = animais.filter((animal) => { return animal.tamanho === "pequeno" }) |
O filter espera uma function por parâmetro com o argumento que é o objeto da iteração atual (como em um foreach) e ela deve retornar um booleano indicando se este objeto fará parte do array de retorno ou não (true indica que ele passou no teste e fará parte).
#15 – ES6: Reduce
Outro recurso importantíssimo dessa geração do ECMAScript, o Reduce permite que façamos agrupamentos e cálculos em cima de coleções de maneira muito fácil e poderosa. Por exemplo, se quisermos somar o peso de todos os animais do nosso array de objetos animais, como faríamos?
1 2 3 4 5 6 7 |
let pesoTotal = 0; for (let i = 0; i < animais.length; i++) { pesoTotal += animais[i].peso; } |
Mas com reduce podemos fazer assim:
1 2 3 4 5 |
let pesoTotal = animais.reduce((total, animal, index, animais) => { return total += animal.peso; }, 0) |
O reduce espera uma function por parâmetro com os seguintes argumentos:
- o primeiro é o valor atual da variável acumuladora (ao término de todas iterações, ele conterá o valor final);
- o segundo argumento é o objeto da iteração atual;
- o terceiro argumento é o índice da iteração atual;
- o quarto argumento é o array com todos objetos que serão iterados;
Esta function será executada uma vez sobre cada objeto do array, retornando o valor agregado ao término de sua execução.
E você, tem alguma dica para adicionar à esta lista? Deixe nos comentários!
Se você quer aprender a ser um programador Node.js e MongoDB, não deixe de conhecer o meu curso clicando no banner abaixo!
Olá, tudo bem?
O que você achou deste conteúdo? Conte nos comentários.