10 Dicas JavaScript
Neste texto separei 10 exemplos que podem te ajudar a reduzir o código e eventualmente melhorar sua legibilidade. Particularmente utilizo estes 10 recursos no meu dia a dia com Node.js e Angular.
[1] Atribuição via desestruturação
A desestruturação de objetos permite pegar valores de um objeto e atribuir à variáveis. Veja abaixo como normalmente fazemos e como podemos fazer com este recurso:
const obj = {
id: 1,
nome: "teste 1",
primeiroAcesso: true
};
const id = obj.id;
const nome = obj.nome;
const obj = {
id: 1,
nome: "teste 1",
primeiroAcesso: true
};
// Aqui "economizamos" uma linha :)
const { id, nome } = obj;
Desestruturação de Array
De forma análoga, podemos utilizar este recurso com array:
const dados = [1, 2, 3, 4];
const [item1, ...demaisItens] = dados;
console.log(item1); // 1
console.log(demaisItens); // [2, 3, 4]
[2] Último item do array com .slice
O .slice
retorna uma cópia de uma determinada parte de um array. O método nos pede a posição inicial e final (opcional) do array que será copiado. Veja no exemplo abaixo:
const meuArray = [1, 2, 3, 4, 5];
console.log(meuArray.slice(2)); // [3, 4, 5]
console.log(meuArray.slice(2, 4)); // [3, 4]
console.log(meuArray.slice(3, 99)); // [4, 5]
Podemos passar um valor negativo como primeiro parâmetro do .slice
para ler os itens do fim para o início do array. Então se passarmos o valor -1
vamos obter o último valor:
const meuArray = [1, 2, 3, 4, 5];
// ao invés de fazer:
const ultimoItemOpcao1 = meuArray[meuArray.length - 1];
// utilize o slice:
const ultimoItemOpcao2 = meuArray.slice(-1);
Observação: existe um método chamado .at
que possibilita chegar no mesmo resultado acima, porém ainda não é suportado pela maioria dos navegadores. Link para mais detalhes.
[3] .find
- procurar um item dentro do array
Ao longo da sua carreira (para os mais velhos rs), com certeza você já precisou buscar um item dentro de um array e se deparou com algo do tipo:
const meuArray = [
{ nome: 'item 1' },
{ nome: 'item 2' },
{ nome: 'item 3' },
];
let item2;
for (let i = 0; i < meuArray.length; i++) {
if (meuArray[i].nome === 'item 2') {
item2 = meuArray[i];
break;
}
}
Utilizando o find
conseguimos reduzir o código de 7 linhas para apenas uma:
const meuArray = [
{ nome: 'item 1' },
{ nome: 'item 2' },
{ nome: 'item 3' },
];
const item2 = meuArray.find(a => a.nome === 'item 2');
Basicamente este método retorna o primeiro item que satisfazer a condição que é passada como parâmetro.
Para quem vêm do .NET C#, o find
é muito similar ao FirstOrDefault
do System.linq
.
[4] .some
- verificar uma condição dentro de um array
De forma parecida com o .find
, o .some
reduz bem as linhas de código retornando true
caso algum item dentro do array satisfaça uma determinada condição. Essa condição é passada como parâmetro do método. Veja abaixo dois exemplos, o primeiro de uma forma mais "tradicional" e o segundo exemplo com o .some
:
const meuArray = [
{ nome: 'item 1' },
{ nome: 'item 2' },
{ nome: 'item 3' },
];
let existeItem2 = false;
for (let i = 0; i < meuArray.length; i++) {
if (meuArray[i].nome === 'item 2') {
existeItem2 = true;
break;
}
}
const meuArray = [
{ nome: 'item 1' },
{ nome: 'item 2' },
{ nome: 'item 3' },
];
const existeItem2 = meuArray
.some(a => a.nome === 'item 2');
Nos dois exemplos a constante existeItem2
terá o valor true
. Veja que o resultado é o mesmo, mas a quantidade de código é muito menor.
[5] Separador númerico
Na versão ES12 foi introduzido a possibilidade de utilizarmos o _
(underline) para ajudar na legibilidade dos números. Exemplo:
const exemplo1 = 10000000;
const exemplo2 = 10_000_000;
console.log(exemplo1 === exemplo2); // true
Para quem trabalha com Angular, este recurso foi incorporado na versão v12.2 para ser utilizado direto no template conforme @mgechev postou no Twitter:
[6] Operador de coalescência nula
Se você já precisou checar se um objeto é null
ou undefined
antes de passar seu valor para uma variável, com certeza o ??
vai te ajudar. Veja abaixo no primeiro exemplo uma forma mais comum de se encontrar essa lógica e na sequência utilizando o ??
.
const usuario = {
nome: null
};
const nomeUsuario1 = usuario.nome !== null
? usuario.nome
: "Sem nome";
console.log(nomeUsuario1); // Sem nome
// ou
let nomeUsuario2 = "Sem nome";
if (usuario.nome) {
nomeUsuario2 = usuario.nome;
}
console.log(nomeUsuario2); // Sem nome
const usuario = {
nome: null
};
const nomeUsuario = usuario.nome ?? "Sem nome";
console.log(nomeUsuario); // Sem nome
Para quem já trabalha um pouco mais de tempo com JavaScript, deve ter visto o ||
ao invés do ??
. A grande diferença é que o ||
sempre retornará o valor do lado direito quando o lado esquerdo retornar false. Este é o grande problema do ||
, pois pode causar resultados não desejados como o exemplo abaixo mostra:
const usuario = {
quantidadeAcessos: 0,
sobrenome: '',
};
console.log(usuario.quantidadeAcessos || 'primeiro acesso');
// 'primeiro acesso'
console.log(usuario.sobrenome || 'não infomado');
// 'não informado'
console.log(usuario.quantidadeAcessos ?? 'primeiro acesso');
// 0
console.log(usuario.sobrenome ?? 'não infomado');
// ''
[7] Como efetuar um distinct em um array
Assim como os outros exemplos, provavelmente você já viu algo do tipo:
const input = [1, 2, 2, 3, 3, 4];
const output = [];
for (let i = 0; i < input.length; i++) {
const item = input[i];
// Simplificamos um pouco utilizando
// o ".some()" citado mais acima
if (!output.some(a => a === item)) {
output.push(item);
}
}
// Fizemos um distinct:
console.log(output); // [1, 2, 3, 4]
Ao invés de realizar toda essa lógica, podemos aproveitar o comportamento padrão do Set
que não permite valores duplicados e não lança erros quando passamos algo duplicado:
const input = [1, 2, 2, 3, 3, 4];
const output = [...(new Set(input)).values()]
console.log(output); // [1, 2, 3, 4]
Para os objetos mais complexos, podemos utilizar o Map
e efetuar o distinct utilizando alguma informação que sirva como chave:
const input = [
{ id: 1, nome: 'JavaScript' },
{ id: 2, nome: 'Angular' },
{ id: 2, nome: 'Angular' },
{ id: 1, nome: 'JavaScript' },
];
// Para cada item dentro do array input,
// criamos um array de duas posições:
// [ <chave/id>, <objeto> ]
const chaveObjeto = input.map(a => [a.id, a]);
// [
// [1, {id: 1, nome: "JavaScript"}],
// [2, {id: 2, nome: "Angular"}],
// [2, {id: 2, nome: "Angular"}],
// [1, {id: 1, nome: "JavaScript"}]
// ]
// De forma similar ao Set, o Map
// não permite chaves duplicadas:
const output = [...(new Map(chaveObjeto)).values()];
console.log(output);
// [
// {id: 1, nome: "JavaScript"},
// {id: 2, nome: "Angular"}
// ]
[8] Medir o tempo de execução com o console.time
Eventualmente precisamos medir o tempo de execução de algum trecho de código. Já vi algumas pessoas instanciando um Date
antes do início do código e um Date
no final para medir o tempo de execução, como abaixo:
const antesDoCodigo = new Date();
setTimeout(() => {
const finalDoCodigo = new Date();
// Diferença em ms
console.log(
(finalDoCodigo.getTime() - antesDoCodigo.getTime())
)
}, 2000);
Ao invés utilizarmos o Date
, podemos utilizar o console.time()
para iniciar o timer e o console.timeEnd()
para finalizar e printar no console o resultado:
console.time();
setTimeout(() => {
// Diferença em ms
console.timeEnd();
}, 2000);
[9] .replace
com expressão regular
O .replace
e as expressões regulares podem ajudar bastante. Particularmente já utilizei este recurso algumas vezes para refatorar códigos que utilizavam várias vezes um substring
para formatar um texto, por exemplo um CPF:
const cpf = '12345678900';
const cpfFormatado = cpf.replace(
/(\d{3})(\d{3})(\d{3})(\d{2})/g,
"$1.$2.$3-$4"
);
console.log(cpfFormatado); // 123.456.789-00
Na expressão regular temos 4 grupos de números (\d
) onde os 3 primeiros grupos tem 3 números ({3}
) e o último 2. O .replace
identifica o valor de cada grupo e permite que seu valor seja utilizado através do prefixo $
seguido do número do grupo:
$1 = "123";
$2 = "456";
$3 = "789";
$4 = "00";
[10] Formatar um JSON com JSON.stringify
Este é um dos meus favoritos, especialmente quando preciso printar algumas informações na tela para entender o que está acontecendo. Veja abaixo o exemplo prestando atenção na diferença dos dois console.log
:
const input = {
campo1: "valor 1",
campo2: "valor 2"
};
console.log(JSON.stringify(input));
// {"campo1":"valor 1","campo2":"valor 2"}
console.log(JSON.stringify(input, null, 4));
/*
{
"campo1": "valor 1",
"campo2": "valor 2"
}
*/
Quando passamos apenas o objeto para o JSON.stringify(obj)
, o resultado é um JSON sem indentação que acaba dificultando a legibilidade quando temos um objeto bem grande. Então podemos utilizar o terceiro parâmetro do stringify
para informar a quantidade de espaços para indentação. Veja mais detalhes aqui.
Considerações
Como citei no início deste post, estes 10 casos abordados acima são parte do meu dia a dia como desenvolvedor e me ajudam bastante. Espero que também te ajude :)
- https://developer.mozilla.org/pt-BR/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment
- https://developer.mozilla.org/pt-BR/docs/Web/JavaScript/Reference/Global_Objects/Array/slice
- https://developer.mozilla.org/pt-BR/docs/Web/JavaScript/Reference/Global_Objects/Array/find
- https://developer.mozilla.org/en-US/docs/Web/API/console/time
- https://developer.mozilla.org/pt-BR/docs/Web/JavaScript/Reference/Global_Objects/String/replace