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
- Distinguir string de number com
typeofeparseInt. - Guardar o que aparece na tela num buffer de texto.
- Evitar
"5" + "5" === "55"quando a conta pede 10. - Quebrar o programa em funções pequenas.
- Usar um
clicksó, no pai dos botões.
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:
Czera tudo, como no carregamento da página.+,-,×e÷guardam a operação e esperam o próximo número.=fecha a conta.- Sem tecla de porcentagem, vírgula ou ponto decimal. Resultados da divisão podem ter uma parte fracionária.
←(extra): se restar um dígito, a tela volta a0.

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
- Por que
"5" + "5"não dá 10? - O que
parseInt("08", 10)devolve, e por que o segundo argumento existe? - Por que um ouvinte no container
.botoessubstitui um ouvinte por botão? - Digite 9,
←, 3,+, 1,=. Qual o resultado esperado?
Respostas comentadas
- Os dois valores são texto. O
+concatena. 10 só aparece depois deparseInt(ou outro conversor) dos dois lados. - 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
10neste volume. - Botões novos entram na grade e já funcionam. O evento sobe até o pai. Você ignora cliques que não vieram de
button. - A seta apaga o 9, a tela fica 0, o 3 entra, soma 1, o resultado é 4.