Organizando seu Código

Você já se perguntou como programadores profissionais conseguem criar aplicações com milhares de linhas de código sem que tudo vire uma bagunça? A resposta está em um dos conceitos mais fundamentais da programação: funções.

Imagine que você está construindo uma casa. Você não mistura todos os materiais de uma vez e espera que algo aconteça. Você divide o trabalho: primeiro a fundação, depois as paredes, o telhado, e assim por diante. Cada etapa é como uma função - uma parte específica do trabalho que pode ser feita de forma independente e reutilizada quando necessário.

Nesta aula, você vai descobrir como as funções transformam código confuso em algo organizado, reutilizável e fácil de entender.

Por Que Funções São Importantes?

Funções: Os Blocos de Construção da Programação

As funções são consideradas os principais "blocos de construção" de qualquer programa porque elas nos permitem três coisas essenciais:

  1. Reutilização de código: Escreva uma vez, use quantas vezes quiser
  2. Organização: Divida problemas grandes em partes menores e gerenciáveis
  3. Isolamento: Cada função cuida de sua própria tarefa sem interferir no restante do código

Pense nas funções como receitas culinárias. Quando você quer fazer um bolo, não inventa tudo do zero cada vez. Você segue uma receita (função) que já funciona. Se quiser fazer vários bolos, usa a mesma receita várias vezes.

Um Exemplo do Mundo Real

Vamos comparar código sem funções e com funções:

Sem funções (confuso e repetitivo):

// Calculando área de três retângulos diferentes
let area1 = 10 * 20;
console.log("Área do retângulo 1:", area1);

let area2 = 15 * 25;
console.log("Área do retângulo 2:", area2);

let area3 = 8 * 12;
console.log("Área do retângulo 3:", area3);

Com funções (organizado e reutilizável):

function calcularAreaRetangulo(largura, altura) {
    return largura * altura;
}

console.log("Área do retângulo 1:", calcularAreaRetangulo(10, 20));
console.log("Área do retângulo 2:", calcularAreaRetangulo(15, 25));
console.log("Área do retângulo 3:", calcularAreaRetangulo(8, 12));

Qual versão é mais clara? Qual seria mais fácil se você precisasse calcular 100 áreas? A resposta é óbvia!

O Que São Funções?

Funções Como Valores Especiais

Em JavaScript, funções não são apenas pedaços de código - elas são valores especiais. Isso significa que você pode:

  • Atribuir funções a variáveis
  • Passar funções como argumentos para outras funções
  • Retornar funções de outras funções
  • Armazenar funções em arrays e objetos

Essa flexibilidade torna JavaScript extremamente poderoso e é fundamental para muitos padrões de programação modernos.

Definição Formal

Uma função é um bloco de código projetado para executar uma tarefa específica. Ela:

  • Pode receber dados de entrada (parâmetros)
  • Processa esses dados
  • Pode devolver um resultado (retorno)
  • Pode ser chamada/executada quantas vezes for necessário

Como Criar Funções

Esta é a forma mais tradicional e comum de criar funções:

function saudacao(nome) {
    console.log("Olá, " + nome + "!");
}

saudacao("Maria"); // Olá, Maria!
saudacao("João");  // Olá, João!

Estrutura:

  • function - palavra-chave que inicia a declaração
  • saudacao - nome da função (escolha nomes descritivos!)
  • (nome) - parâmetros entre parênteses
  • { } - corpo da função entre chaves

Hoisting: Uma Característica Especial

Declarações de função têm uma característica única chamada hoisting (içamento). Isso significa que você pode chamar a função antes mesmo de declará-la no código:

// Isso funciona! A declaração é "içada" para o topo
cumprimentar("Ana");

function cumprimentar(pessoa) {
    console.log("Bem-vindo(a), " + pessoa + "!");
}

Isso acontece porque durante a fase de compilação do JavaScript, todas as declarações de função são processadas primeiro, ficando disponíveis em todo o escopo.

Parâmetros e Argumentos

Qual é a Diferença?

Muitas pessoas confundem esses termos, mas há uma diferença conceitual importante:

  • Parâmetros: São as variáveis listadas entre parênteses na definição da função
  • Argumentos: São os valores reais passados para a função quando ela é chamada
function analisarArray(dados, limite) { // 'dados' e 'limite' são PARÂMETROS
    let resultado = [];
    
    for (let i = 0; i < dados.length; i++) {
        if (dados[i] >= limite) {
            resultado.push(dados[i]);
        }
    }
    
    return resultado;
}

let notas = [85, 92, 78, 96, 88];
let notasAltas = analisarArray(notas, 90); // 'notas' e '90' são ARGUMENTOS

console.log(notasAltas); // [92, 96]

Valores Padrão (Default Parameters)

Você pode especificar valores padrão para parâmetros. Isso torna suas funções mais flexíveis e tolerantes a diferentes formas de uso:

function criarIntervalo(inicio, fim, passo = 1) { // 'passo' tem valor padrão 1
    let resultado = [];
    
    for (let i = inicio; i <= fim; i += passo) {
        resultado.push(i);
    }
    
    return resultado;
}

console.log(criarIntervalo(1, 10));     // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
console.log(criarIntervalo(0, 20, 5));  // [0, 5, 10, 15, 20]

Por que isso é útil? Porque permite que a função funcione de forma sensata mesmo quando alguns valores não são fornecidos, tornando-a mais flexível.

Retornando Valores

O Que é Return?

A instrução return permite que uma função devolva um valor de volta para o código que a chamou:

function encontrarMaior(numeros) {
    if (numeros.length === 0) {
        return undefined; // retorno antecipado
    }
    
    let maior = numeros[0];
    
    for (let i = 1; i < numeros.length; i++) {
        if (numeros[i] > maior) {
            maior = numeros[i];
        }
    }
    
    return maior;
}

let valores = [45, 23, 89, 12, 67];
console.log(encontrarMaior(valores)); // 89
console.log(encontrarMaior([]));      // undefined

Funções Sem Return

Quando uma função não tem return ou tem return sem valor, ela retorna undefined:

function exibirMensagem(texto) {
    console.log(texto);
    // sem return - retorna undefined implicitamente
}

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

Escopo de Variáveis

O Que é Escopo?

Escopo é a região do código onde uma variável pode ser acessada. É como a "visibilidade" da variável.

let variavelGlobal = "Eu sou global!";

function minhaFuncao() {
    let variavelLocal = "Eu sou local!";
    
    console.log(variavelGlobal); // ✅ Funciona - acessa variável global
    console.log(variavelLocal);  // ✅ Funciona - acessa variável local
}

minhaFuncao();

console.log(variavelGlobal); // ✅ Funciona
console.log(variavelLocal);  // ❌ Erro! Variável não existe aqui

Regras de Escopo

  1. Variáveis globais: Acessíveis em qualquer lugar do código
  2. Variáveis locais: Acessíveis apenas dentro da função onde foram declaradas
  3. Variáveis de bloco (let/const): Acessíveis apenas dentro do bloco { } onde foram declaradas
function exemplo() {
    if (true) {
        let dentroDoBloco = "Só existe aqui";
        console.log(dentroDoBloco); // ✅ Funciona
    }
    
    console.log(dentroDoBloco); // ❌ Erro! Fora do escopo
}

Boas Práticas com Funções

1. Nomenclatura Descritiva

Funções são ações, então use verbos que indiquem claramente o que fazem:

// ❌ Ruim - nomes vagos
function processar(d) { }
function fazer() { }
function x(a, b) { }

// ✅ Bom - nomes descritivos
function calcularTotalCompra(itens) { }
function validarEmail(endereco) { }
function converterTemperatura(celsius) { }

2. Uma Função, Uma Responsabilidade

Cada função deve fazer uma coisa e fazer bem:

// ❌ Ruim - função faz muitas coisas
function processarUsuario(dados) {
    // valida dados
    // salva no banco
    // envia email
    // gera relatório
    // etc...
}

// ✅ Bom - funções específicas
function validarDadosUsuario(dados) { }
function salvarUsuario(usuario) { }
function enviarEmailBoasVindas(email) { }
function gerarRelatorioUsuario(usuario) { }

3. Parâmetros em Quantidade Razoável

Evite funções com muitos parâmetros (mais de 3-4 já é bastante):

// ❌ Difícil de usar
function criar(n, i, e, s, c, t, p) { }

// ✅ Melhor - use um objeto
function criarUsuario(dados) {
    let { nome, idade, email, senha, cidade, telefone, pais } = dados;
    // ...
}

criarUsuario({
    nome: "Maria",
    idade: 28,
    email: "maria@email.com",
    senha: "senha123",
    cidade: "São Paulo",
    telefone: "11999999999",
    pais: "Brasil"
});

4. Evite Modificar Variáveis Externas

Prefira funções que não modificam o estado externo (funções puras):

// ❌ Função impura - modifica variável externa
let contador = 0;
function incrementar() {
    contador++; // modifica variável global
    return contador;
}

// ✅ Função pura - não modifica estado externo
function incrementarPuro(valor) {
    return valor + 1; // retorna novo valor
}

let meuContador = 0;
meuContador = incrementarPuro(meuContador);

Por que isso importa? Funções puras são mais previsíveis, mais fáceis de testar e menos propensas a bugs.

Exemplos Práticos

Exemplo 1: Validador de CPF Simples

function validarCPF(cpf) {
    // Remove caracteres não numéricos
    let cpfLimpo = cpf.replace(/\D/g, '');
    
    // Verifica se tem 11 dígitos
    if (cpfLimpo.length !== 11) {
        return false;
    }
    
    // Verifica se todos os dígitos são iguais
    let todosIguais = true;
    for (let i = 1; i < cpfLimpo.length; i++) {
        if (cpfLimpo[i] !== cpfLimpo[0]) {
            todosIguais = false;
            break;
        }
    }
    
    if (todosIguais) {
        return false;
    }
    
    return true; // Validação simplificada
}

console.log(validarCPF("123.456.789-10")); // true
console.log(validarCPF("111.111.111-11")); // false
console.log(validarCPF("12345"));          // false

Exemplo 2: Calculadora de Desconto

function calcularPrecoComDesconto(preco, percentualDesconto = 0) {
    if (preco < 0) {
        return 0;
    }
    
    if (percentualDesconto < 0 || percentualDesconto > 100) {
        return preco; // sem desconto se percentual inválido
    }
    
    let desconto = preco * (percentualDesconto / 100);
    let precoFinal = preco - desconto;
    
    return precoFinal;
}

console.log(calcularPrecoComDesconto(100));      // 100
console.log(calcularPrecoComDesconto(100, 10));  // 90
console.log(calcularPrecoComDesconto(100, 25));  // 75
console.log(calcularPrecoComDesconto(100, -5));  // 100 (percentual inválido)

Exemplo 3: Formatador de Nome

function formatarNome(nomeCompleto) {
    // Divide o nome em palavras
    let palavras = nomeCompleto.trim().split(' ');
    
    // Formata cada palavra
    let palavrasFormatadas = [];
    for (let i = 0; i < palavras.length; i++) {
        if (palavras[i].length > 0) {
            let palavra = palavras[i].toLowerCase();
            let primeiraLetra = palavra[0].toUpperCase();
            let restoLetra = palavra.slice(1);
            palavrasFormatadas.push(primeiraLetra + restoLetra);
        }
    }
    
    // Junta tudo novamente
    return palavrasFormatadas.join(' ');
}

console.log(formatarNome("MARIA SILVA"));        // Maria Silva
console.log(formatarNome("joão   pedro  costa")); // João Pedro Costa
console.log(formatarNome("  ana    maria  "));   // Ana Maria

Exemplo 4: Analisador de Array

function analisarNumeros(numeros) {
    if (numeros.length === 0) {
        return {
            soma: 0,
            media: 0,
            maior: undefined,
            menor: undefined
        };
    }
    
    let soma = 0;
    let maior = numeros[0];
    let menor = numeros[0];
    
    for (let i = 0; i < numeros.length; i++) {
        soma += numeros[i];
        
        if (numeros[i] > maior) {
            maior = numeros[i];
        }
        
        if (numeros[i] < menor) {
            menor = numeros[i];
        }
    }
    
    let media = soma / numeros.length;
    
    return {
        soma: soma,
        media: media,
        maior: maior,
        menor: menor
    };
}

let notas = [7.5, 8.0, 9.5, 6.0, 8.5];
let analise = analisarNumeros(notas);

console.log("Soma:", analise.soma);     // 39.5
console.log("Média:", analise.media);   // 7.9
console.log("Maior:", analise.maior);   // 9.5
console.log("Menor:", analise.menor);   // 6.0

Por Que Isso É Importante?

Funções transformam programação de uma tarefa confusa em algo organizado e gerenciável. Elas são a base para criar código profissional, limpo e manutenível. Dominar funções é o primeiro passo para se tornar um programador de verdade!

Próximos Passos

Na próxima aula, vamos explorar:

  • Arrow Functions em mais detalhes
  • Callbacks: funções como argumentos
  • Closures: o poder de preservar escopos
  • Aplicações avançadas de funções

"Funções são como ferramentas em uma caixa. Quanto mais ferramentas você tiver e melhor souber usá-las, mais complexos serão os projetos que você poderá construir."