Funções são blocos de construção fundamentais em JavaScript. Elas permitem encapsular um conjunto de instruções que podem ser executadas sob demanda, promovendo organização, reutilização e clareza no código. Nesta aula, exploraremos os conceitos básicos de funções: como declará-las e expressá-las, como trabalhar com parâmetros e valores de retorno, e como o reuso de funções torna o desenvolvimento mais eficiente.

Declaração vs expressão

Em JavaScript, existem duas maneiras principais de definir uma função: através de uma declaração de função (function declaration) e através de uma expressão de função (function expression). Embora ambas criem funções, elas possuem diferenças sutis, especialmente em relação ao hoisting (elevação).

Declaração de função: Usa a palavra-chave function seguida do nome da função. A declaração é hoisted (elevada) para o topo do escopo, o que significa que você pode chamar a função antes mesmo de sua declaração no código.

// Declaração de função
function saudacao(nome) {
  return "Olá, " + nome + "!";
}

// Chamada antes da declaração (funciona devido ao hoisting)
console.log(saudacao("Maria")); // "Olá, Maria!"

Expressão de função: A função é atribuída a uma variável. Nesse caso, a função não é hoisted; a variável é hoisted, mas a atribuição ocorre apenas na linha onde está. Portanto, você não pode chamar a expressão antes de sua definição.

// Expressão de função
const saudacao = function(nome) {
  return "Olá, " + nome + "!";
};

console.log(saudacao("João")); // "Olá, João!"
// console.log(outraSaudacao("Ana")); // Erro! (não hoisted)

Outra diferença importante é que declarações de função podem ser nomeadas, enquanto expressões podem ser anônimas ou nomeadas. As expressões nomeadas são úteis para depuração e recursão.

Parâmetros e retorno

Funções podem receber dados de entrada, chamados parâmetros, e podem devolver um valor através da instrução return. Parâmetros são como variáveis locais que recebem os valores passados na chamada da função (argumentos).

Exemplo básico:

function somar(a, b) {
  return a + b;
}

console.log(somar(5, 3)); // 8

Uma função pode ter zero ou mais parâmetros. Se nenhum return for especificado, a função retorna undefined. O return também interrompe a execução da função imediatamente.

function mostrarMensagem(mensagem) {
  console.log(mensagem);
  // sem return explícito
}

let resultado = mostrarMensagem("Olá!"); // "Olá!"
console.log(resultado); // undefined

Parâmetros podem ter valores padrão (a partir do ES6), que são usados se o argumento for undefined:

function cumprimentar(nome = "visitante") {
  return "Bem-vindo, " + nome + "!";
}

console.log(cumprimentar()); // "Bem-vindo, visitante!"
console.log(cumprimentar("Ana")); // "Bem-vindo, Ana!"

Reuso

Um dos principais benefícios das funções é a capacidade de reutilizar código. Em vez de repetir a mesma lógica em vários lugares, você define uma função uma vez e a chama sempre que necessário. Isso torna o código mais enxuto, fácil de manter e menos propenso a erros.

Exemplo: suponha que você precise calcular a área de vários círculos. Sem função, você repetiria a fórmula várias vezes:

// Sem reuso
let raio1 = 3;
let area1 = Math.PI * raio1 * raio1;

let raio2 = 5;
let area2 = Math.PI * raio2 * raio2;

let raio3 = 7;
let area3 = Math.PI * raio3 * raio3;

Com uma função, você define a lógica uma vez e a reutiliza:

// Com reuso
function calcularAreaCirculo(raio) {
  return Math.PI * raio * raio;
}

let area1 = calcularAreaCirculo(3);
let area2 = calcularAreaCirculo(5);
let area3 = calcularAreaCirculo(7);

Além de reuso, funções facilitam a manutenção: se a fórmula mudar (por exemplo, usar Math.PI * raio ** 2), você altera apenas um lugar.

Funções também podem ser passadas como argumentos para outras funções (callbacks), retornadas de funções (closures), e armazenadas em estruturas de dados, ampliando ainda mais as possibilidades de reuso.

Boas práticas

  • Prefira declarações de função para funções que serão chamadas antes da definição (hoisting).
  • Use expressões de função quando precisar atribuir a uma variável ou passar como callback.
  • Dê nomes descritivos para funções, indicando o que elas fazem (ex: calcularMedia, validarEmail).
  • Mantenha funções pequenas e com uma única responsabilidade.
  • Evite efeitos colaterais: prefira retornar valores a modificar variáveis globais.

Referências

Exercícios

  1. Crie uma declaração de função chamada dobro que recebe um número e retorna o dobro dele. Em seguida, chame a função com o valor 7 e exiba o resultado no console.

    ✓ Resposta:
    function dobro(numero) {
      return numero * 2;
    }
    
    console.log(dobro(7)); // 14
  2. Converta a função do exercício anterior em uma expressão de função (anônima) atribuída a uma constante chamada dobroExp. Teste chamando-a com o valor 4.

    ✓ Resposta:
    const dobroExp = function(numero) {
      return numero * 2;
    };
    
    console.log(dobroExp(4)); // 8
  3. Escreva uma função chamada saudacaoPersonalizada que recebe dois parâmetros: nome e periodo (por exemplo, "manhã", "tarde", "noite"). A função deve retornar uma string como "Bom dia, João!". Se o período não for fornecido, use "dia" como padrão.

    ✓ Resposta:
    function saudacaoPersonalizada(nome, periodo = "dia") {
      return `Bom ${periodo}, ${nome}!`;
    }
    
    console.log(saudacaoPersonalizada("João", "manhã")); // "Bom manhã, João!"
    console.log(saudacaoPersonalizada("Maria")); // "Bom dia, Maria!"
  4. Crie uma função chamada calcularMedia que recebe três números como parâmetros e retorna a média aritmética deles. Em seguida, use essa função para calcular a média de 8, 9 e 10.

    ✓ Resposta:
    function calcularMedia(a, b, c) {
      return (a + b + c) / 3;
    }
    
    console.log(calcularMedia(8, 9, 10)); // 9
  5. Explique com suas palavras a diferença entre declaração de função e expressão de função, mencionando o hoisting. Dê um exemplo de código que demonstre o hoisting em ação.

    ✓ Resposta:

    Na declaração de função, a função é hoisted (elevada) para o topo do escopo, permitindo que seja chamada antes de sua definição no código. Na expressão de função, apenas a variável é hoisted, mas a atribuição da função ocorre no local, então a chamada antes da definição resulta em erro. Exemplo:

    // Declaração: funciona
    console.log(soma(2, 3)); // 5
    function soma(a, b) { return a + b; }
    
    // Expressão: erro
    console.log(subtrai(5, 2)); // TypeError: subtrai is not a function
    const subtrai = function(a, b) { return a - b; };