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

Testes automatizados com Jest
Testes automatizados com Jest

Existe um momento na vida de todo desenvolvedor em que ele mexe em um código...

Criando um servidor HTTP com Node.js puro
Criando um servidor HTTP com Node.js puro

Antes de usar o Express — o framework que simplifica tudo — é fundamental ent...

Introdução ao TypeScript
Introdução ao TypeScript

JavaScript é uma linguagem dinamicamente tipada. Isso significa que uma variá...