Javascript

Mini Projeto: Calculadora no Console Já leu

9 min de leitura

Mini Projeto: Calculadora no Console
Chegamos ao fim do primeiro módulo. Em nove artigos você percorreu um caminho sólido — da sintaxe básica até conceitos q

Chegamos ao fim do primeiro módulo. Em nove artigos você percorreu um caminho sólido — da sintaxe básica até conceitos que muitos desenvolvedores levam meses para entender de verdade.

Este artigo tem dois objetivos: primeiro, revisar os conceitos centrais do módulo com exemplos rápidos. Segundo, construir um projeto real que une tudo em um único programa funcional. Projetos são onde o aprendizado se consolida — teoria sem prática esquece rápido.

Vamos revisar e construir.


Revisão rápida — Módulo 1


Variáveis e tipos

const nome = "Ricardo";      // string imutável
let pontos = 0;              // número mutável
const ativo = true;          // boolean
const endereco = null;       // ausência intencional
let profissao;               // undefined

// Template literal
console.log(`${nome} tem ${pontos} pontos.`);

Condicionais

const nota = 7.5;

if (nota >= 9) {
  console.log("Excelente");
} else if (nota >= 6) {
  console.log("Aprovado");
} else {
  console.log("Reprovado");
}

// Ternário
const status = nota >= 6 ? "Aprovado" : "Reprovado";

Laços

// for clássico
for (let i = 0; i < 5; i++) {
  console.log(i);
}

// for...of
const frutas = ["maçã", "banana", "laranja"];
for (const fruta of frutas) {
  console.log(fruta);
}

// while
let tentativas = 3;
while (tentativas > 0) {
  console.log(`Tentativas restantes: ${tentativas}`);
  tentativas--;
}

Funções

// Declaração
function somar(a, b) { return a + b; }

// Expressão
const subtrair = function(a, b) { return a - b; };

// Arrow
const multiplicar = (a, b) => a * b;

// Parâmetros padrão
const saudar = (nome = "visitante") => `Olá, ${nome}!`;

Arrays

const numeros = [1, 2, 3, 4, 5];

const dobrados = numeros.map(n => n * 2);
const pares = numeros.filter(n => n % 2 === 0);
const soma = numeros.reduce((acc, n) => acc + n, 0);

Objetos

const usuario = {
  nome: "Ana",
  idade: 28,
  saudar() {
    return `Olá, sou ${this.nome}!`;
  },
};

const { nome, idade } = usuario; // desestruturação
const copia = { ...usuario };    // spread

Escopo e Closures

function criarContador() {
  let count = 0;
  return {
    incrementar: () => ++count,
    valor: () => count,
  };
}

const contador = criarContador();
contador.incrementar();
contador.incrementar();
console.log(contador.valor()); // 2

Tratamento de erros

function dividir(a, b) {
  if (b === 0) throw new Error("Divisão por zero.");
  return a / b;
}

try {
  console.log(dividir(10, 0));
} catch (erro) {
  console.log(`Erro: ${erro.message}`);
} finally {
  console.log("Operação finalizada.");
}

Mini Projeto — Calculadora no Console

Agora vamos construir uma calculadora completa que aplica tudo do Módulo 1. Ela terá:

  • Operações básicas: soma, subtração, multiplicação, divisão
  • Operações avançadas: potência, resto, raiz quadrada
  • Histórico de operações
  • Validação de entrada com tratamento de erros
  • Memória (guardar e recuperar um valor)
  • Relatório final com estatísticas

Construiremos em partes, do mais simples ao mais complexo.


Parte 1 — Operações básicas

// Erros personalizados
class ErroCalculadora extends Error {
  constructor(mensagem) {
    super(mensagem);
    this.name = "ErroCalculadora";
  }
}

// Validação de entradas
function validarNumeros(...valores) {
  for (const valor of valores) {
    if (typeof valor !== "number" || isNaN(valor)) {
      throw new ErroCalculadora(`"${valor}" não é um número válido.`);
    }
  }
}

// Operações — cada uma faz apenas uma coisa
const operacoes = {
  somar: (a, b) => {
    validarNumeros(a, b);
    return a + b;
  },

  subtrair: (a, b) => {
    validarNumeros(a, b);
    return a - b;
  },

  multiplicar: (a, b) => {
    validarNumeros(a, b);
    return a * b;
  },

  dividir: (a, b) => {
    validarNumeros(a, b);
    if (b === 0) throw new ErroCalculadora("Divisão por zero não é permitida.");
    return a / b;
  },

  potencia: (base, expoente) => {
    validarNumeros(base, expoente);
    return base ** expoente;
  },

  resto: (a, b) => {
    validarNumeros(a, b);
    if (b === 0) throw new ErroCalculadora("Divisão por zero não é permitida.");
    return a % b;
  },

  raizQuadrada: (a) => {
    validarNumeros(a);
    if (a < 0) throw new ErroCalculadora("Não é possível calcular raiz de número negativo.");
    return Math.sqrt(a);
  },
};

Parte 2 — A fábrica da calculadora (closures + objetos)

function criarCalculadora() {
  // Estado privado — acessível apenas pelos métodos
  const historico = [];
  let memoria = null;
  let totalOperacoes = 0;
  let totalErros = 0;

  // Registra operação no histórico
  function registrar(expressao, resultado) {
    totalOperacoes++;
    const entrada = {
      numero: totalOperacoes,
      expressao,
      resultado,
      horario: new Date().toLocaleTimeString("pt-BR"),
    };
    historico.push(entrada);
    console.log(`[${entrada.numero}] ${expressao} = ${resultado}`);
    return resultado;
  }

  // Executa uma operação com tratamento de erros
  function executar(operacao, expressao, ...args) {
    try {
      const resultado = operacao(...args);
      return registrar(expressao, resultado);
    } catch (erro) {
      totalErros++;
      console.log(`❌ Erro: ${erro.message}`);
      return null;
    }
  }

  // Interface pública da calculadora
  return {
    somar(a, b) {
      return executar(operacoes.somar, `${a} + ${b}`, a, b);
    },

    subtrair(a, b) {
      return executar(operacoes.subtrair, `${a} - ${b}`, a, b);
    },

    multiplicar(a, b) {
      return executar(operacoes.multiplicar, `${a} × ${b}`, a, b);
    },

    dividir(a, b) {
      return executar(operacoes.dividir, `${a} ÷ ${b}`, a, b);
    },

    potencia(base, exp) {
      return executar(operacoes.potencia, `${base} ^ ${exp}`, base, exp);
    },

    resto(a, b) {
      return executar(operacoes.resto, `${a} % ${b}`, a, b);
    },

    raizQuadrada(a) {
      return executar(operacoes.raizQuadrada, `√${a}`, a);
    },

    // Memória
    salvarMemoria(valor) {
      if (typeof valor !== "number" || isNaN(valor)) {
        console.log("❌ Valor inválido para memória.");
        return;
      }
      memoria = valor;
      console.log(`💾 Memória salva: ${memoria}`);
    },

    recuperarMemoria() {
      if (memoria === null) {
        console.log("⚠️  Memória vazia.");
        return null;
      }
      console.log(`💾 Memória: ${memoria}`);
      return memoria;
    },

    limparMemoria() {
      memoria = null;
      console.log("💾 Memória limpa.");
    },

    // Histórico
    verHistorico() {
      if (historico.length === 0) {
        console.log("Nenhuma operação realizada ainda.");
        return;
      }
      console.log("\n📋 HISTÓRICO DE OPERAÇÕES:");
      console.log("─".repeat(40));
      historico.forEach(({ numero, expressao, resultado, horario }) => {
        console.log(`  [${numero}] ${horario} | ${expressao} = ${resultado}`);
      });
      console.log("─".repeat(40));
    },

    // Relatório final com estatísticas
    relatorio() {
      const resultados = historico.map(h => h.resultado).filter(r => r !== null);

      const maior = resultados.length > 0 ? Math.max(...resultados) : null;
      const menor = resultados.length > 0 ? Math.min(...resultados) : null;
      const media = resultados.length > 0
        ? (resultados.reduce((acc, r) => acc + r, 0) / resultados.length).toFixed(2)
        : null;

      console.log("\n📊 RELATÓRIO DA SESSÃO:");
      console.log("═".repeat(40));
      console.log(`  Total de operações : ${totalOperacoes}`);
      console.log(`  Operações com erro : ${totalErros}`);
      console.log(`  Operações válidas  : ${totalOperacoes - totalErros}`);
      console.log(`  Maior resultado    : ${maior}`);
      console.log(`  Menor resultado    : ${menor}`);
      console.log(`  Média dos resultados: ${media}`);
      console.log(`  Memória atual      : ${memoria ?? "vazia"}`);
      console.log("═".repeat(40));
    },
  };
}

Parte 3 — Usando a calculadora

const calc = criarCalculadora();

console.log("🔢 CALCULADORA JAVASCRIPT\n");

// Operações básicas
calc.somar(10, 5);          // [1] 10 + 5 = 15
calc.subtrair(20, 8);       // [2] 20 - 8 = 12
calc.multiplicar(6, 7);     // [3] 6 × 7 = 42
calc.dividir(100, 4);       // [4] 100 ÷ 4 = 25

// Operações avançadas
calc.potencia(2, 10);       // [5] 2 ^ 10 = 1024
calc.resto(17, 5);          // [6] 17 % 5 = 2
calc.raizQuadrada(144);     // [7] √144 = 12

// Testando erros
calc.dividir(10, 0);        // ❌ Divisão por zero
calc.raizQuadrada(-9);      // ❌ Raiz de negativo
calc.somar("abc", 5);       // ❌ Valor inválido

// Memória
calc.salvarMemoria(calc.somar(3, 7)); // salva 10
calc.recuperarMemoria();              // 💾 Memória: 10
calc.multiplicar(calc.recuperarMemoria(), 5); // 10 × 5 = 50
calc.limparMemoria();

// Histórico e relatório
calc.verHistorico();
calc.relatorio();

Parte 4 — Saída esperada no console

🔢 CALCULADORA JAVASCRIPT

[1] 10 + 5 = 15
[2] 20 - 8 = 12
[3] 6 × 7 = 42
[4] 100 ÷ 4 = 25
[5] 2 ^ 10 = 1024
[6] 17 % 5 = 2
[7] √144 = 12
❌ Erro: Divisão por zero não é permitida.
❌ Erro: Não é possível calcular raiz de número negativo.
❌ Erro: "abc" não é um número válido.
[8] 3 + 7 = 10
💾 Memória salva: 10
💾 Memória: 10
[9] 10 × 5 = 50
💾 Memória limpa.

📋 HISTÓRICO DE OPERAÇÕES:
────────────────────────────────────────
  [1] 10:32:15 | 10 + 5 = 15
  [2] 10:32:15 | 20 - 8 = 12
  [3] 10:32:15 | 6 × 7 = 42
  [4] 10:32:15 | 100 ÷ 4 = 25
  [5] 10:32:15 | 2 ^ 10 = 1024
  [6] 10:32:15 | 17 % 5 = 2
  [7] 10:32:15 | √144 = 12
  [8] 10:32:15 | 3 + 7 = 10
  [9] 10:32:15 | 10 × 5 = 50
────────────────────────────────────────

📊 RELATÓRIO DA SESSÃO:
════════════════════════════════════════
  Total de operações  : 12
  Operações com erro  : 3
  Operações válidas   : 9
  Maior resultado     : 1024
  Menor resultado     : 2
  Média dos resultados: 243.56
  Memória atual       : vazia
════════════════════════════════════════

O que este projeto exercitou

Conceito Onde apareceu
const e let Estado interno da calculadora
Condicionais Validações e tratamento de casos especiais
Funções e arrow functions Todas as operações e helpers
Objetos e métodos Interface pública e objeto operacoes
Arrays e métodos Histórico, map, filter, reduce
Desestruturação forEach no histórico
Spread operator Math.max(...resultados)
Escopo Estado privado da calculadora
Closures historico, memoria, totalOperacoes privados
Classes de erro ErroCalculadora
try/catch/finally executar()
Template literals Todas as mensagens formatadas

Desafio final do Módulo 1

Expanda a calculadora com pelo menos duas das funcionalidades abaixo:

  1. Método desfazer() que remove a última operação do histórico
  2. Método filtrarHistorico(operador) que retorna apenas operações de um tipo (ex: só somas)
  3. Método exportarHistorico() que retorna o histórico como string formatada
  4. Suporte a cálculos encadeados: calc.somar(5, 3).multiplicar(2) retornando 16
  5. Método limpar() que zera todo o estado da calculadora

Conclusão do Módulo 1

Parabéns. Você completou o primeiro módulo da série. Em dez artigos você aprendeu:

  • Variáveis, tipos e operadores
  • Estruturas condicionais e switch
  • Laços de repetição
  • Funções em todas as suas formas
  • Arrays com map, filter e reduce
  • Objetos, métodos e this
  • Desestruturação, spread e rest
  • Escopo, hoisting e closures
  • Tratamento de erros robusto
  • Como unir tudo em um projeto real

No próximo módulo saímos do console e entramos no navegador — vamos aprender a manipular o DOM, reagir a eventos e criar interfaces interativas com JavaScript puro.


📌 Próximo artigo: Aula 11 — O que é o DOM e como o JavaScript interage com o HTML 🎯 Início do Módulo 2 — JavaScript no Navegador


📚 Fontes e Referências

Comentários

Mais em Javascript

Async/Await: escrevendo código assíncrono de forma limpa
Async/Await: escrevendo código assíncrono de forma limpa

As Promises resolveram o Callback Hell. Mas encadear muitos&nbsp;.then() aind...

Escopo, Hoisting e Closures
Escopo, Hoisting e Closures

Este &eacute; um dos artigos mais importantes da s&eacute;rie. N&atilde;o por...

Funções: declaração, expressão e arrow functions
Funções: declaração, expressão e arrow functions

Se os la&ccedil;os evitam a repeti&ccedil;&atilde;o de a&ccedil;&otilde;es, a...