Certificações ProfissionaisCursos e Qualificações

10 exercícios de JavaScript: teste seus conhecimentos

Treine suas habilidades com 10 exercícios de JavaScript baseados em problemas reais do dia a dia



Em resumo:

  • Praticar exercícios de JavaScript é o caminho mais rápido para sair da teoria e dominar a lógica de programação no dia a dia.
  • Os desafios abordam problemas diretos de código. A lista segue uma ordem de dificuldade progressiva para ajudar você a evoluir passo a passo nos estudos.
  • Ao final do conteúdo, uma tabela com o gabarito completo permite validar suas respostas e entender a melhor solução para cada código.

Aprender a programar em JavaScript exige mais do que horas de leitura e vídeos teóricos. É preciso colocar a mão na massa e aplicar o que você aprendeu na prática.

É pensando nisso que a Revista Quero preparou 10 exercícios sobre JavaScript que simulam situações cotidianas para quem trabalha com a tecnologia.

Pegue seu editor de código favorito e tente resolver cada etapa antes de consultar o gabarito no final do artigo.

Exercício 1

A equipe financeira de um grande e-commerce solicitou uma função que calcule o faturamento líquido de produtos da categoria "eletronicos" que já estão com status "aprovado", aplicando ainda um desconto fixo de taxa de processamento de 5% sobre o valor de cada item válido.

Teste vocacional

Qual carreira combina com o seu perfil?

Responda as perguntas e descubra o curso certo e as bolsas ideais para você!

JavaScript

const transacoes = [
  { id: 101, categoria: 'eletronicos', valor: 1000, status: 'aprovado' },
  { id: 102, categoria: 'eletronicos', valor: 500, status: 'pendente' },
  { id: 103, categoria: 'vestuario', valor: 200, status: 'aprovado' },
  { id: 104, categoria: 'eletronicos', valor: 2000, status: 'aprovado' }
];

Qual das implementações abaixo resolve esse problema de forma declarativa, imutável e retornando exatamente o valor esperado (2850)?

  • A) transacoes.filter(t => t.categoria === 'eletronicos' && t.status === 'aprovado').reduce((acc, t) => acc + (t.valor * 0.95));
  • B) transacoes.filter(t => t.categoria === 'eletronicos' && t.status === 'aprovado').reduce((acc, t) => acc + (t.valor * 0.95), 0);
  • C) transacoes.map(t => t.categoria === 'eletronicos' && t.status === 'aprovado' ? t.valor * 0.95 : 0).filter((acc, val) => acc + val);
  • D) transacoes.forEach(t => { if (t.categoria === 'eletronicos' && t.status === 'aprovado') return t.valor * 0.95; });

Exercício 2

Durante a Black Friday, o servidor de busca da plataforma começou a apresentar lentidão extrema. Ao investigar os logs da aplicação front-end, o componente de barra de pesquisa dispara uma requisição HTTP (fetch) a cada evento input (ou seja, a cada letra digitada pelo usuário).

Para corrigir isso sem bibliotecas externas, você decide implementar uma função debounce, garantindo que a busca só ocorra quando o usuário fizer uma pausa de 300ms na digitação.

Qual implementação cria corretamente esse mecanismo utilizando Closures e controle de Timers?

  • A)

JavaScript

function debounce(fn, delay) {
  let timer;
  return function(...args) {
    clearTimeout(timer);
    timer = setTimeout(() => fn.apply(this, args), delay);
  };
}
  • B)

JavaScript

function debounce(fn, delay) {
  return function(...args) {
    let timer = setTimeout(() => fn(...args), delay);
    clearTimeout(timer);
  };
}
  • C)

JavaScript

function debounce(fn, delay) {
  let timer = setTimeout(fn, delay);
  return function(...args) {
    if (timer) return;
    fn(...args);
  };
}
  • D)

JavaScript

function debounce(fn, delay) {
  return setInterval(() => {
    fn();
  }, delay);
}

Exercício 3

Em uma aplicação SPA (Single Page Application) que utiliza comparação por referência (shallow comparison) para detectar mudanças de estado e atualizar a tela, um desenvolvedor júnior abriu um chamado informando que a interface não atualiza quando o usuário altera o tema do sistema de "claro" para "escuro".

Ao revisar o código dele, você encontra a seguinte estrutura de estado:

JavaScript

const estadoUsuario = {
  id: 99,
  nome: 'Mariana',
  configuracoes: {
    notificacoes: true,
    aparencia: {
      tema: 'claro',
      fonte: 'media'
    }
  }
};

Sabendo que o objeto original estadoUsuario e seus sub-objetos afetados não podem sofrer mutação direta (precisam de uma nova referência em memória), qual código gera o novo estado corretamente?

  • A) const novoEstado = Object.assign(estadoUsuario, { configuracoes: { aparencia: { tema: 'escuro' } } });
  • B) const novoEstado = { ...estadoUsuario }; novoEstado.configuracoes.aparencia.tema = 'escuro';
  • C) const novoEstado = { ...estadoUsuario, configuracoes: { ...estadoUsuario.configuracoes, aparencia: { ...estadoUsuario.configuracoes.aparencia, tema: 'escuro' } } };
  • D) const novoEstado = { ...estadoUsuario, configuracoes: { aparencia: { tema: 'escuro' } } };

Exercício 4

Você está construindo o painel inicial (Dashboard) de um sistema bancário. Ao fazer login, a tela dispara três chamadas assíncronas independentes simultaneamente: buscarSaldo(), buscarExtrato() e buscarOfertasCartao().

Atualmente, o sistema utiliza Promise.all(). O problema é que o microsserviço de ofertas de cartão cai com frequência, e quando isso acontece, o Promise.all() rejeita tudo e o cliente fica impedido de ver até mesmo o próprio saldo.

Qual abordagem resolve essa situação-problema, permitindo que as requisições rodem em paralelo e você consiga aproveitar os dados das que tiveram sucesso mesmo que uma delas falhe?

  • A) Substituir por três blocos await sequenciais dentro de um único try/catch, pois assim o erro de uma promessa será ignorado automaticamente pelas demais.
  • B) Utilizar Promise.race([buscarSaldo(), buscarExtrato(), buscarOfertasCartao()]), que garante o retorno de todas as promessas que não deram erro primeiro.
  • C) Utilizar Promise.allSettled([buscarSaldo(), buscarExtrato(), buscarOfertasCartao()]) e filtrar os resultados pelo status === 'fulfilled' para extrair os valores (value).
  • D) Utilizar Promise.any([buscarSaldo(), buscarExtrato(), buscarOfertasCartao()]), pois ele aguarda todas finalizarem e retorna um array apenas com as bem-sucedidas.

Exercício 5

O líder de atendimento ao cliente pediu uma nova visualização em formato Kanban em que os chamados (tickets) abertos no dia sejam separados em colunas de acordo com sua prioridade ("alta", "media", "baixa").

O back-end entrega apenas um array plano de objetos. Você precisa transformar essa lista em um objeto indexado pelas prioridades em uma única passagem (O(n))

JavaScript

const chamados = [
  { protocolo: 'A1', prioridade: 'alta' },
  { protocolo: 'A2', prioridade: 'baixa' },
  { protocolo: 'A3', prioridade: 'alta' }
];

Qual alternativa realiza esse agrupamento de maneira limpa e moderna?

  • A) chamados.reduce((acc, item) => { (acc[item.prioridade] ??= []).push(item); return acc; }, {});
  • B) chamados.map(item => ({ [item.prioridade]: [item] }));
  • C) chamados.filter(item => item.prioridade).reduce((acc, item) => acc[item.prioridade] = item, {});
  • D) Object.fromEntries(chamados.map(item => [item.prioridade, [item]]));

Exercício 6

Ao refatorar um módulo legado para usar a sintaxe de Classes do JavaScript, você criou uma classe UploadService responsável por enviar arquivos ao servidor quando o usuário clica em um botão da interface.

Porém, ao clicar no botão no navegador, o console dispara o erro: TypeError: Cannot read properties of undefined (reading 'endpoint').

JavaScript

class UploadService {
  constructor() {
    this.endpoint = 'https://api.empresa.com/upload';
  }

  enviarArquivo() {
    console.log(`Enviando para ${this.endpoint}`);
  }
}

const servico = new UploadService();
const botao = document.querySelector('#btn-upload');
botao.addEventListener('click', servico.enviarArquivo);

Por que esse erro ocorre nesse cenário real e qual a forma padrão de corrigi-lo?

  • A) O erro ocorre porque variáveis iniciadas no constructor são privadas. Corrige-se declarando endpoint fora da classe como uma variável global.
  • B) O erro ocorre porque o addEventListener altera o contexto do this dentro de enviarArquivo para referenciar o próprio elemento HTML (botao). Corrige-se passando servico.enviarArquivo.bind(servico) ou declarando enviarArquivo = () => { ... } (Arrow Function) na classe.
  • C) O erro ocorre porque o método enviarArquivo não é assíncrono (async). Corrige-se adicionando a palavra-chave async antes do nome do método.
  • D) O erro ocorre porque document.querySelector não suporta métodos de instâncias de classes. Corrige-se usando botao.onclick = servico.enviarArquivo().

Exercício 7

Na linha do tempo de uma rede social corporativa, o usuário faz a rolagem da página (scroll infinito) para carregar mais publicações.

Como novos posts são criados a todo segundo por outros funcionários, a paginação do banco de dados às vezes retorna na página 2 um post que já havia acabado de aparecer no fim da página 1.

Para evitar que o mesmo post apareça duplicado na tela, você precisa mesclar a lista antiga com a nova e remover objetos que possuam o mesmo id, mantendo apenas um registro por id.

Qual solução resolve esse problema com complexidade linear (sem usar loops aninhados lentos como filter com findIndex)?

  • A) const unicos = [...new Set([...postsAntigos, ...postsNovos])];
  • B) const unicos = [...new Map([...postsAntigos, ...postsNovos].map(post => [post.id, post])).values()];
  • C) const unicos = Object.values([...postsAntigos, ...postsNovos]);
  • D) const unicos = postsAntigos.concat(postsNovos).sort((a, b) => a.id !== b.id);

Exercício 8

Sua aplicação consome dados cadastrais de uma API governamental instável. Nem todos os cidadãos possuem endereço completo ou telefone cadastrado; às vezes o nó endereco vem como null, outras vezes nem sequer existe no JSON retornado.

O código atual frequentemente quebra a aplicação inteira com erro de referência ao tentar exibir o nome da cidade:

JavaScript

// Código atual problemático:
const nomeCidade = respostaApi.dados.cidadao.endereco.cidade.nome;

Caso qualquer propriedade dessa cadeia seja null ou undefined, o sistema deve atribuir o texto "Não informada" à variável nomeCidade (incluindo o caso em que nome venha como null ou undefined, mas preservando caso fosse uma string vazia proposital "").

Qual sintaxe moderna resolve isso em uma única linha?

  • A) const nomeCidade = respostaApi.dados.cidadao.endereco.cidade.nome || 'Não informada';
  • B) const nomeCidade = respostaApi?.dados?.cidadao?.endereco?.cidade?.nome ?? 'Não informada';
  • C) const nomeCidade = respostaApi?.dados?.cidadao?.endereco?.cidade?.nome && 'Não informada';
  • D) const nomeCidade = try { respostaApi.dados.cidadao.endereco.cidade.nome } catch { 'Não informada' };

Exercício 9

Um desenvolvedor criou uma rotina para sincronizar o estoque de uma lista de produtos consultando uma API externa para cada item.

Ele tentou usar o método forEach com async/await para aguardar cada produto ser processado antes de exibir a mensagem de conclusão:

JavaScript

async function sincronizarEstoque(idsProdutos) {
  idsProdutos.forEach(async (id) => {
    await atualizarProdutoNaApi(id);
  });
  console.log('Sincronização 100% concluída!');
}

Em produção, o log 'Sincronização 100% concluída!' aparece instantaneamente no console, antes mesmo da primeira requisição terminar, gerando inconsistência no relatório subsequente.

Por que isso acontece e como corrigir para que as requisições sejam aguardadas (em série ou em paralelo)?

  • A) O forEach não aguarda o retorno de Promises passadas no seu callback. Para rodar em série (um após o outro), deve-se usar o loop for...of com await; para rodar em paralelo e aguardar todos, deve-se usar await Promise.all(idsProdutos.map(id => atualizarProdutoNaApi(id))).
  • B) O await dentro de uma Arrow Function é ignorado pelo motor do JavaScript. Basta trocar async (id) => por async function(id) dentro do próprio forEach.
  • C) O método forEach só funciona de forma assíncrona se colocarmos await idsProdutos.forEach(...) no início da linha.
  • D) O console.log no JavaScript sempre tem prioridade na Call Stack sobre funções async, sendo obrigatório colocá-lo dentro de um setTimeout de 0ms.

Exercício 10

Em uma página de listagem de imóveis, o usuário pode aplicar vários filtros (ex: ?cidade=sp&quartos=3&mobiliado=true).

Para que o usuário possa copiar o link da página e enviar para outra pessoa no WhatsApp mantendo os filtros aplicados, sua aplicação precisa ler a Query String da URL no momento em que a página carrega e transformá-la em um objeto JavaScript simples ({ cidade: 'sp', quartos: '3', mobiliado: 'true' }) para preencher o estado inicial dos filtros.

Qual combinação nativa do JavaScript realiza essa conversão de forma direta e segura?

  • A) const filtros = JSON.parse(window.location.search);
  • B) const filtros = Object.fromEntries(new URLSearchParams(window.location.search));
  • C) const filtros = window.location.search.split('&').reduce((acc, item) => acc + item, {});
  • D) const filtros = new Map(window.location.href);

Gabarito Comentado

ExercícioAlternativa CorretaJustificativa Técnica
1BO filter isola apenas os aprovados da categoria alvo e o reduce acumula os valores aplicando 0.95. O segundo argumento 0 no reduce é indispensável; sem ele (como na A), o acumulador iniciaria com o primeiro objeto inteiro do array, resultando em concatenação incorreta ("[object Object]1900").
2AA Closure mantém a variável timer viva entre as chamadas. A cada novo evento dentro da janela de tempo, clearTimeout(timer) cancela o agendamento anterior e setTimeout reinicia a contagem de 300ms.
3CEm estados aninhados, é necessário clonar (...) cada nível até a propriedade alterada (shallow copy em cascata). A opção B altera a referência interna diretamente (mutação), e a D apaga as propriedades irmãs (notificacoes e fonte).
4CDiferente do Promise.all (que aplica fail-fast e aborta tudo se uma falhar), o Promise.allSettled aguarda todas as promessas terminarem, retornando o status individual (fulfilled ou rejected) de cada serviço.
5AO uso do reduce combinado com o operador Logical Nullish Assignment (??=) inicializa o array daquela chave caso ainda não exista e já insere (push) o item correspondente. A opção D sobrescreveria chaves repetidas.
6BPassar servico.enviarArquivo como callback desacopla o método da instância servico, fazendo o this apontar para o elemento disparador do evento (botao). O .bind(servico) ou uma Arrow Function como propriedade de classe trava o this léxico na instância correta.
7BUm Set (opção A) só remove duplicatas de tipos primitivos ou se os objetos tiverem exatamente a mesma referência de memória. Já o Map indexado por [post.id, post] sobrescreve chaves de mesmo id em tempo $O(n)$, e .values() extrai os objetos únicos.
8BO Optional Chaining (?.) evita o erro TypeError retornando undefined caso algum elo da corrente não exista. O Nullish Coalescing (??) retorna o valor padrão apenas se a expressão à esquerda for null ou undefined.
9AO método forEach apenas dispara as funções de callback em um loop síncrono sem observar as Promises retornadas. Para controle de fluxo assíncrono, utiliza-se for...of (execução sequencial) ou map com Promise.all (execução concorrente).
10Bnew URLSearchParams(window.location.search) faz o parse seguro dos parâmetros da URL (lidando inclusive com caracteres especiais codificados), e Object.fromEntries() converte o iterador de pares [chave, valor] diretamente em um objeto literal.

Como aprender JavaScript do zero ao avançado?

Se você quer aprender JavaScript do zero ao avançado, com projetos reais e suporte de carreira, conte com a Allevo Tech.

Na plataforma, você encontra trilhas de aprendizado personalizadas e mentorias com especialistas na área que vão te levar do zero ao domínio absoluto da programação.

Além disso, só na Allevo Tech, você garante certificações a cada novo módulo concluído, garantindo que os seus conhecimentos sejam reconhecidos no mercado de trabalho.

Clique no botão abaixo e conheça as formações da Allevo Tech que podem impulsionar a sua trajetória profissional.

Logo do Querobolsa

Gostando da matéria?

Inscreva-se e receba nossos principais posts no seu e-mail

Banner FOQA Últimas Notícias

Revista Vídeos

As profissões mais bem pagas em 2026

Postado em 31/03/2026

Como estudar pro ENEM 2026 do ZERO

Postado em 23/04/2026


Pronto para estudar pagando menos?

Bolsas de até 80% de desconto em milhares de faculdades por todo o Brasil.
Encontrar minha bolsa