10 Dicas JavaScript

10 dicas para melhorar seu código JavaScript. Veja exemplos como atribuição via desestruturação, como efetuar um distinct, nullish entre outros

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 :)