Pular para o conteúdo
murad.guide

As Três Camadas

Capítulo 20

Calculadora com JavaScript

4 min de leitura 759 palavras 1 gravura

O capítulo 12 deixou a calculadora da Oficina desenhada: tela, grade, botões. Esta liga o comportamento. Entrada por dígitos inteiros; uma divisão pode produzir resultado fracionário. Sem % e sem ponto decimal. O botão ← é extra: apaga o último dígito.

O exemplo pronto está em exemplos/20-calculadora-js/. A marcação e o CSS são os da etapa 12. O que entra agora é calculadora.js e um único ouvinte no container .botoes.

Trabalhe na cópia inicio desta etapa. Leia e digite o código indicado; mude apenas uma coisa. Antes de recarregar, escreva o resultado que espera. Depois compare com a referência completa ao lado. Se algo falhar, confira primeiro o arquivo salvo e o caminho aberto.

O que você vai aprender

A tela da 12, o cérebro nesta pasta

Copie de exemplos/12-calculadora-html/ o HTML e o CSS, ou abra direto exemplos/20-calculadora-js/. No fim do body:

<script src="calculadora.js"></script>

Sem esse arquivo, os botões não fazem nada. Com ele, cada clique atualiza .tela.

Regras desta calculadora:

Calculadora da Oficina: tela e grade de botões inteiros

Buffer string, conta number

Tudo que você lê do DOM chega como texto. typeof "5" é "string". typeof 5 é "number".

console.log("5" + "5");
console.log(parseInt("5", 10) + parseInt("5", 10));

A primeira linha imprime 55: + entre strings concatena. A segunda imprime 10. parseInt(texto, 10) lê um inteiro na base 10.

O buffer é a string da tela. Enquanto a pessoa digita, você só cola dígitos. Na hora de somar, converte.

let total = 0;
let buffer = "0";
let operador = null;
const tela = document.querySelector(".tela");

total é o número já acumulado. operador é +, -, ×, ÷ ou null se ainda não houve operação.

Erro comum: fazer buffer + 5 misturando tipos. Se buffer for "3", o resultado vira "35". Converta só na conta, não a cada dígito.

Pare e experimente. No console, rode typeof document.querySelector(".tela").textContent. Deve ser "string", mesmo quando a tela mostra 0.

Funções pequenas e um ouvinte só

Vários botões, um pai. O clique sobe até .botoes. Você escuta o pai e pergunta quem foi o target.

document.querySelector(".botoes").addEventListener("click", (evento) => {
  const botao = evento.target.closest("button");
  if (!botao) return;
  clicar(botao.textContent.trim());
});

closest("button") pega o botão mesmo se o clique acertar um filho. trim tira espaços do ←.

function clicar(valor) {
  if (Number.isNaN(parseInt(valor, 10))) {
    simbolo(valor);
  } else {
    numero(valor);
  }
  tela.textContent = buffer;
}

function numero(valor) {
  if (buffer === "0" || buffer === "Erro") buffer = valor;
  else buffer += valor;
}

Se o texto do botão não é um dígito, cai em simbolo. Senão, entra no buffer.

Símbolos, igual e a seta

function calcular(n) {
  if (operador === "÷" && n === 0) {buffer="Erro";total=0;operador=null;return false;}
  if (operador === "+") total += n;
  else if (operador === "-") total -= n;
  else if (operador === "×") total *= n;
  else if (operador === "÷") total /= n;
  return true;
}

function simbolo(valor) {
  if (valor === "C") {
    total = 0;
    buffer = "0";
    operador = null;
    return;
  }
  if (valor === "←") {
    buffer = buffer.length === 1 ? "0" : buffer.slice(0, -1);
    return;
  }
  if (valor === "=") {
    if (!operador) return;
    if (!calcular(Number(buffer))) return;
    buffer = String(total);
    total = 0;
    operador = null;
    return;
  }
  if ("+-×÷".includes(valor)) {
    const n = Number(buffer);
    if (operador) {if (!calcular(n)) return;}
    else total = n;
    operador = valor;
    buffer = "0";
  }
}

Divisão por zero mostra Erro. C reinicia; um novo dígito também inicia outra entrada. Ao reutilizar uma divisão, Number(buffer) preserva a parte fracionária; parseInt a descartaria. Depois de =, o buffer vira texto de novo com String(total).

Não junte tudo numa função gigante. Cada função faz uma coisa: dígito, símbolo, conta, desenho da tela.

Conferir

Abra o exemplo. Faça 7 + 5 = e espere 12, não 75. Aperte C. A tela volta a 0. Digite 40, ←, ←: a tela vai a 4 e depois a 0.

Se a conta “cola” números, você ainda está somando strings. Coloque console.log(typeof total, typeof buffer) dentro de calcular enquanto investiga. Tire os logs no fim.

O foco visível dos botões já está no CSS da 12. Percorra com Tab e acione com Enter: o clique nativo do botão basta, porque o ouvinte está no container.

Atividades

  1. Por que "5" + "5" não dá 10?
  2. O que parseInt("08", 10) devolve, e por que o segundo argumento existe?
  3. Por que um ouvinte no container .botoes substitui um ouvinte por botão?
  4. Digite 9, ←, 3, +, 1, =. Qual o resultado esperado?

Respostas comentadas

  1. Os dois valores são texto. O + concatena. 10 só aparece depois de parseInt (ou outro conversor) dos dois lados.
  2. Devolve 8. A base 10 deixa explícita a leitura decimal; zeros à esquerda não são interpretados como octal no JavaScript atual. Sempre passe 10 neste volume.
  3. Botões novos entram na grade e já funcionam. O evento sobe até o pai. Você ignora cliques que não vieram de button.
  4. A seta apaga o 9, a tela fica 0, o 3 entra, soma 1, o resultado é 4.

Referências