How to build a calculator with JavaScript

Javitocor
6 min readAug 5, 2020

--

Basic calculator using JS

Photo by Markus Spiske on Unsplash

One interesting project I had to build in my very early experience with JavaScript was a basic calculator. It was a bit challenging due that I was a newbie with this language, but I like challenges so I started to think a little and this is what came out…

The first thing I did was to plan the whole process that I was going to carry out, how I was going to structure the code and what kind of functions I would need. After a few minutes thinking about it, I wrote it down on paper and opened my VSCode.

Step 1
Create an HTML file using CSS and generate the calculator image on the screen. This is the simplest part.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Calculator</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css" integrity="sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk" crossorigin="anonymous">
<link rel="stylesheet" type="text/css" href="./style/style.css">
</head>
<body class="bg-secondary">
<nav class="navbar navbar-dark bg-dark">
<span class="navbar-brand mb-0 h1 text-success">Calculator</span>
<button type="button" class="btn btn-success" data-toggle="modal" data-target="#exampleModalCenter">
Instructions
</button>
</nav>
<div id="calc" class="w-50 mx-auto my-5">
<table class="w-100">
<tr>
<td colspan="4"><input type="text" id="result"/></td>

</tr>
<tr>
<td colspan="2"><input type="button" value="c" id="clear"/> </td>
<td colspan="2"><input type="button" value="back" id="back"/> </td>
</tr>
<tr>
<td><input type="button" value="1" id="1"/> </td>
<td><input type="button" value="2" id="2"/> </td>
<td><input type="button" value="3" id="3"/> </td>
<td><input type="button" value="/" id="div"/> </td>
</tr>
<tr>
<td><input type="button" value="4" id="4"/> </td>
<td><input type="button" value="5" id="5"/> </td>
<td><input type="button" value="6" id="6"/> </td>
<td><input type="button" value="-" id="sub"/> </td>
</tr>
<tr>
<td><input type="button" value="7" id="7"/> </td>
<td><input type="button" value="8" id="8"/> </td>
<td><input type="button" value="9" id="9"/> </td>
<td><input type="button" value="+" id="add"/> </td>
</tr>
<tr>
<td><input type="button" value="." id="dec"/> </td>
<td><input type="button" value="0" id="0"/> </td>
<td><input type="button" value="=" id="equal"/> </td>
<td><input type="button" value="*" id="mult"/> </td>
</tr>
</table>
</div>
<!-- Modal -->
<div class="modal fade" id="exampleModalCenter" tabindex="-1" role="dialog" aria-labelledby="exampleModalCenterTitle" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLongTitle">Instructions</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<ul class="list-group">
<li class="list-group-item list-group-item-success">Add first number clicking on</li>
<li class="list-group-item list-group-item-success">Click operator</li>
<li class="list-group-item list-group-item-success">Add second number clicking on</li>
<li class="list-group-item list-group-item-success">Click '=' to see the result</li>
<li class="list-group-item list-group-item-success">Press 'C' to reset the values</li>
</ul>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-success" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.min.js" integrity="sha384-OgVRvuATP1z7JjHLkuOU7Xw704+h835Lr+6QL9UvYjZE3Ipu6Tp75j7Bh/kR0JKI" crossorigin="anonymous"></script>
<script src="script.js"></script>
</body>
</html>

Step 2
Create the vanilla JS calculator and check that it works. To do this, I first wrote some basic tests with Jest for each of the operations and to make sure that the code I was going to write worked correctly.
Then create a function with the four basic operations (addition, subtraction, multiplication and division), nothing to write home about. I run the test and everything was working fine. So the first step of my planning was successful, one Hurray! for me …

const calculator =  function calculator(){
function add(...args) {
if([...args].length === 0) return 0;
return [...args].reduce(function sum(sum, value){return sum + value}, 0);
}
function subtract(...args) {
if([...args].length === 0) return 0;
return [...args].reduce(function sum(diff, value){return diff - value});
}
function divide(x, y) {
if(y === 0){
return 'ERROR! Cannot divide by 0'
}
return x / y;
}
function multiply(...args) {
if([...args].length === 0) return 0;
return [...args].reduce(function sum(prod, value){return prod * value}, 1);
}
return { add, subtract, divide, multiply }
}

Step 3
Once verified that the calculator function was working I went to the next phase. Create the operate function that, with the data that the user enters, the corresponding operation applies to me.

function operate (operator, value1, value2) {
value1 = checkNumber(value1);
value2 = checkNumber(value2);
if(operator === 'add'){
return calculator().add(value1, value2);
} else if (operator === 'sub'){
return calculator().subtract(value1, value2);
} else if (operator === 'mult') {
return calculator().multiply(value1, value2);
} else if (operator === 'div'){
return calculator().divide(value1, value2);
}
};

Step 4
After that, I needed to store the user data and pass it to my function. So I needed to add some event listeners for each element of my HTML and pass them to a logical function that would define what information is (number, decimal, operand, equal …)

const buttons = document.querySelectorAll('input[type="button"]');
buttons.forEach(button => button.addEventListener('click', function () {
getValue(button.id);
}));

Step 5
Create the getValue function to manage all user input and also display them on the screen.

let temp = '';
let temp2 = '';
let op = '';
const text = document.querySelector('input[type="text"]');

function getValue(value) {
if(isNaN(value) === false && op === '') {
temp += value;
text.value = temp;
} else if (isNaN(value) === true && temp === '' && temp2 === '') {
op = '';
temp = '';
temp2 = '';
} else if (isNaN(value) === true && value !== 'clear' && value !== 'dec' && op === '' && value !== 'back') {
op = value;
} else if (isNaN(value) === false && op !== ''){
temp2 += value;
text.value = temp2;
} else if (isNaN(value) === true && temp !== '' & temp2 !== '' && value !== 'clear' && value !== 'dec' && value !== 'back'){
temp = operate(op, temp, temp2);
temp2 = '';
text.value = temp;
} else if (isNaN(value) === true && value === 'dec' && op === '' && !temp.includes('.')) {
temp += '.';
text.value = temp;
} else if (isNaN(value) === true && value === 'dec' && op !== '' && !temp2.includes('.')) {
temp2 += '.';
text.value = temp2;
} else if (isNaN(value) === true && value === 'clear') {
clear();
} else if (isNaN(value) === true && value !== 'clear' && value !== 'dec' && value !== 'back' && op !== '') {
op = value;
} else if (isNaN(value) === true && value === 'back' && op === '') {
temp = text.value.slice(0, -1);
text.value = temp;
} else if (isNaN(value) === true && value === 'back' && op !== '') {
temp2 = text.value.slice(0, -1);
text.value = temp2;
}
}

And ready….

…Well, no! I had some small bugs that I had to solve. For example, decimal numbers. To do this, create a helper function to check whether the user’s input was an integer or a float.

function checkNumber(number) {
if(/^\d+\.\d+$/.test(number)){
return number = parseFloat(number);
} else {
return number = parseInt(number);
}
};

And now, yes … voila! Operational calculator!

As it was Sunday and it rained I decided to add keyboard support to my calculator and not have to use only the mouse.

const btn1 = document.getElementById('1');
const btn2 = document.getElementById('2');
const btn3 = document.getElementById('3');
const btn4 = document.getElementById('4');
const btn5 = document.getElementById('5');
const btn6 = document.getElementById('6');
const btn7 = document.getElementById('7');
const btn8 = document.getElementById('8');
const btn9 = document.getElementById('9');
const btn0 = document.getElementById('0');
const btnDecimal = document.getElementById('dec');
const btnEqual = document.getElementById('equal');
const btnDivide = document.getElementById('div');
const btnMultiply = document.getElementById('mult');
const btnSubtract = document.getElementById('sub');
const btnAdd = document.getElementById('add');
const btnClear = document.getElementById('clear');
const btnBack = document.getElementById('back');


document.addEventListener("keypress", e => {
switch (e.key) {
case '1':
btn1.click();
break;
case '2':
btn2.click();
break;
case '3':
btn3.click();
break;
case '4':
btn4.click();
break;
case '5':
btn5.click();
break;
case '6':
btn6.click();
break;
case '7':
btn7.click();
break;
case '8':
btn8.click();
break;
case '9':
btn9.click();
break;
case '0':
btn0.click();
break;
case '.':
btnDecimal.click();
break;
case '=':
btnEqual.click();
break;
case '/':
btnDivide.click();
break;
case '*':
btnMultiply.click();
break;
case '-':
btnSubtract.click();
break;
case '+':
btnAdd.click();
break;
case 'c':
btnClear.click();
break;
case 'Enter':
btnEqual.click();
break;
case 'Backspace':
btnBack.click();
break;
}
});

And now yes, basic calculator working with mouse and keyboard build with vanilla JavaScript.

You can check it out on my Github.

--

--