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