Respostas

Desafios de Funções em JavaScript: Pratique e Domine!

Nível Básico (Questões 1-8)

  1. Uma função é um bloco de código reutilizável projetado para executar uma tarefa específica. Os três principais benefícios são:

    1. Organizar o código: Separam tarefas complexas em partes menores e mais gerenciáveis.

    2. Evitar repetição: Você escreve a lógica uma vez e a chama quantas vezes precisar.

    3. Facilitar a manutenção: Corrigir um bug em uma função corrige o problema em todos os lugares onde ela é usada.

  • Palavra-chave: function (inicia a declaração da função).

  • Nome da função: calcularMedia (o nome que usamos para chamar a função).

  • Parâmetros: nota1 e nota2 (as "variáveis" que a função espera receber).

  • Valor de retorno: (nota1 + nota2) / 2 (o cálculo que a instrução return envia de volta).

  • Parâmetros: São as variáveis listadas na definição da função (ex: nota1, nota2). Eles agem como espaços reservados para os valores que a função receberá.

  • Argumentos: São os valores reais passados para a função quando ela é chamada (ex: calcularMedia(8, 9), onde 8 e 9 são os argumentos).

const despedida = function() {
  // Esta função não tem nome, por isso é anônima.
  // Ela foi atribuída à variável 'despedida'.
  console.log("Até logo!");
};

despedida(); // Chama a função através da variável.
  1. A principal vantagem é a sintaxe mais curta e compacta. Elas permitem escrever funções de forma mais limpa e rápida, especialmente para operações de uma única linha.

// Para um único parâmetro, os parênteses são opcionais.
// Como há apenas uma instrução, as chaves {} e a palavra 'return' podem ser omitidas.
const quadrado = n => n * n;

console.log(quadrado(4)); // Vai mostrar: 16
  1. Não, uma função não precisa ter return.

  • Com return: A função executa seu código e devolve um valor para quem a chamou. Esse valor pode ser armazenado em uma variável.

  • Sem return: A função apenas executa uma ação (como imprimir algo no console), mas não devolve um valor. O resultado da chamada de uma função sem return é sempre undefined.

function boasVindas(nome) {
  // Usar template string (crase) é uma forma moderna e legível de montar strings.
  console.log(`Bem-vindo(a), ${nome}! 😊`);
}

boasVindas("Marina"); // Vai mostrar: Bem-vindo(a), Marina! 😊

Nível Intermediário (Questões 9-18)

  1. A "pilha de chamadas" é um mecanismo que o JavaScript usa para controlar a execução das funções. Cada vez que uma função é chamada, ela é "empilhada" (adicionada ao topo da pilha). Quando a função termina (encontra um return ou o final do seu bloco), ela é "desempilhada" (removida do topo). Isso garante que o fluxo do programa sempre retorne ao ponto correto após a conclusão de uma função.

  2. A declaração tradicional (function nome() {}) sofre hoisting. Isso significa que a declaração da função é "movida" para o topo do seu escopo pelo JavaScript antes da execução do código. Na prática, isso permite que você chame a função antes mesmo de declará-la no código, o que não acontece com expressões de função ou arrow functions.

  3. O resultado será:

cachorro
gato
  • O primeiro console.log está dentro da função mostrarAnimal, que tem sua própria variável animal ("cachorro") em seu escopo local. Ela usa essa variável.

  • O segundo console.log está fora da função, no escopo global. Ele acessa a variável animal global, cujo valor é "gato".

  1. O nome mais adequado é verificarLogin. Ele segue as convenções de usar um verbo (verificar) para indicar uma ação e camelCase para juntar palavras de forma legível. Nomes como check são genéricos e funcao_de_login usa um padrão diferente (snake_case).

  2. A função retornará undefined. O erro comum é esquecer a palavra-chave return. Embora o cálculo a - b seja feito e armazenado em resultado, a função não devolve esse valor para quem a chamou.

  3. Uma IIFE (Immediately Invoked Function Expression) é uma função que é declarada e executada no mesmo instante. Sua principal utilidade é criar um escopo isolado para evitar que variáveis "vazem" para o escopo global e causem conflitos com outras partes do código.

  • soma(5, 10, 15): O argumento extra (15) é simplesmente ignorado. A função usará apenas os dois primeiros (5 e 10), e o resultado será 15.

  • soma(5): O segundo parâmetro (b) não recebe um argumento, então seu valor se torna undefined. A operação 5 + undefined resulta em NaN (Not a Number).

// Adicionamos um valor padrão ao parâmetro nome.
// Se nenhum argumento for passado, "visitante" será usado.
function saudacao(nome = "visitante") {
  console.log(`Olá, ${nome}!`);
}

saudacao("Lucas"); // Olá, Lucas!
saudacao();       // Olá, visitante!
  1. É uma função que faz pelo menos uma das seguintes coisas:

    1. Recebe uma ou mais funções como argumento (callback).

    2. Retorna uma função como seu resultado. Exemplo: O método .map() de arrays é uma função de ordem superior, pois recebe uma função como argumento para aplicar a cada item.

  2. O valor de resultado será undefined. A função console.log exibe um valor no terminal, mas seu próprio valor de retorno é undefined. Como a função mostrarAlerta retorna o resultado de console.log, ela acaba retornando undefined.


Nível Avançado (Questões 19-30)

  1. Closure é a capacidade de uma função "lembrar" e acessar as variáveis do escopo onde ela foi criada, mesmo que esse escopo já tenha sido encerrado. No exemplo criarContador, a função interna retornada ainda tem acesso à variável contador da função externa criarContador, mesmo após criarContador já ter sido executada.

  2. A função retornará 100. O parâmetro "rest" (...numeros) coleta todos os argumentos passados (10, 20, 30, 40) e os transforma em um array [10, 20, 30, 40]. O método reduce então soma todos os elementos desse array.

  • setTimeout(callback, tempo): Executa a função de callback uma única vez após o tempo especificado.

  • setInterval(callback, tempo): Executa a função de callback repetidamente, a cada tempo especificado, até que seja interrompido (com clearInterval).

  1. Um "callback" é uma função que é passada como argumento para outra função, com a intenção de ser executada mais tarde.

function processar(numero, callback) {
  let resultado = numero * 2;
  callback(resultado); // "Chamando de volta" a função recebida
}

// Usando console.log como callback:
processar(10, console.log); // Vai mostrar: 20
  1. Uma função recursiva é uma função que chama a si mesma dentro de seu próprio corpo. O elemento essencial é a condição de parada (ou caso base). É uma verificação que impede a função de se chamar infinitamente, evitando que a pilha de chamadas estoure (stack overflow).

  2. É desaconselhado por motivos de segurança e performance. Ele avalia o código a partir de uma string, o que é semelhante a usar eval(). Isso pode abrir brechas de segurança (injeção de código) e é mais lento para o motor do JavaScript otimizar do que funções declaradas normalmente.

  3. O objeto arguments é um objeto "parecido com um array" (array-like) que contém todos os argumentos passados para uma função (exceto em arrow functions). O parâmetro "rest" (...) é preferido porque:

    1. Ele cria um array de verdade, permitindo o uso direto de métodos como .map(), .filter(), etc.

    2. É mais explícito e legível, deixando claro que a função pode receber múltiplos argumentos.

  4. Ocorrerá um erro: TypeError: soma is not a function. A declaração da função soma foi sobrescrita pela linha let soma = 10;. No momento em que soma() é chamada, a variável soma contém o número 10, e não uma função, portanto não pode ser invocada com ().

  • Caso 1: Funciona por causa do hoisting. As declarações de função (function nome(){}) são "elevadas" ao topo do escopo, então mostrarMensagem já é conhecida quando é chamada.

  • Caso 2: Gera um ReferenceError. Funções atribuídas a variáveis com const (ou let) não sofrem hoisting. A tentativa de chamar mostrarMensagem2 ocorre antes de sua inicialização, causando o erro.

function avaliarAluno(nota1, nota2) {
  const media = (nota1 + nota2) / 2;
  if (media >= 7) {
    return "Aprovado";
  } else if (media >= 5) {
    return "Recuperação";
  } else {
    return "Reprovado";
  }
}
console.log(avaliarAluno(8, 6)); // Média 7 -> Aprovado
function calcularNotas(...notas) {
  if (notas.length === 0) return 0; // Evita divisão por zero
  const soma = notas.reduce((total, nota) => total + nota, 0);
  return soma / notas.length;
}
console.log(calcularNotas(7, 8, 9, 10)); // Deve retornar: 8.5
function repetir(callback, n) {
  // O laço vai de 0 até n-1, executando n vezes.
  for (let i = 0; i < n; i++) {
    callback(); // Executa a função recebida.
  }
}

repetir(() => console.log("Praticar leva à perfeição!"), 3);

Last updated