[Javascript] 초간단 계산기 프로그램 만들기
아주 아주 간단한 사칙 연산을 하는 계산기 프로그램을 만들어 보겠습니다.
일반적인 계산기 기능을 모두 하려면 퍼센트 값, 괄호, 소수점, 지우기 버튼이 있는 한 줄이 더 필요한데 여기서는 숫자와 사칙 연산만 하는 계산기를 만듭니다.
언제나 그렇지만 최소한의 코드로 최적의 기능을 구현하는 것이 목적이기 때문에 30줄 안쪽의 자바스크립트 코드만으로 계산기 기능을 구현합니다.
사칙 연산의 결과를 얻는 과정이 일반적으로 사용하는 연산자별로 구분을 해서 계산을 하지 않고 입력한 계산식 자체를 실행 가능한 함수로 이벨류에이션(Evaluation)해서 결과를 즉시 얻는 최신의 방법을 사용합니다.
0. 완성 소스코드 다운로드
1. 계산기 버튼 화면 배치
화면 버튼은 총 16개가 필요합니다. 사칙 연산만 가능한 계산기이므로 0~9 숫자, +,-,*,/,=,AC 버튼을 만들면 됩니다.
래퍼로 사용하는 "numpad" 클래스 하위로 다음과 같이 HTML 코드를 만들면 됩니다.
<div class="numpad">
<div><span>1</span></div>
<div><span>2</span></div>
<div><span>3</span></div>
<div class="operator"><span>+</span></div>
<div><span>4</span></div>
<div><span>5</span></div>
<div><span>6</span></div>
<div class="operator"><span>-</span></div>
<div><span>7</span></div>
<div><span>8</span></div>
<div><span>9</span></div>
<div class="operator"><span>*</span></div>
<div><span>0</span></div>
<div class="allclear"><span>AC</span></div>
<div class="calc"><span>=</span></div>
<div class="operator"><span>/</span></div>
</div>
만드는 방식에 따라서는 자바스크립트 코드로 버튼 태그를 동적으로 생성해서 붙일 수도 있습니다.
다만, 불필요하게 자바스크립트 코드가 길어지고, HTML 태그로 표현하는 것이 더 깔끔하고 단순하기 때문에 그렇게 추천하지는 않습니다.
const btnarr = ['1','2','3','+','4','5','6','-','7','8','9','*','0','AC','=','/']
btnarr.forEach((val,idx)=>{
let btn = document.createElement('div')
let txt = document.createElement('span')
txt.innerText = val
console.log(parseInt(val))
if(val == "AC"){
//AC
btn.classList.add('allclear')
}else if(isNaN(parseInt(val))){
//연산자
btn.classList.add('operator')
}
btn.appendChild(txt)
document.querySelector('.numpad').appendChild(btn)
})
계산기 버튼의 레이아웃도 최대한 단순하게 일렬로 배치를 합니다.
플렉스(Flex)나 그리드(Grid)로 구현해도 되지만, 초간단 계산기이므로 레이아웃도 초간단 구조로 구현합니다.
채색 및 그림자 효과 등 장식적인 요소들을 제외하고 나면 실제 CSS에서 중요한 부분은 몇가지 되지 않습니다.
버튼을 마우스로 눌렀을 때 버튼이 눌린 효과를 내기 위해 입체감을 내는 그림자 효과를 없애는 것은 :active 가상 선택자로 상태 토글을 합니다.
.numpad{
font-size: 2em;
font-weight: bold;
}
.numpad > div{
position: relative;
float: left;
width: 60px;
height: 60px;
border-radius: .75em;
box-shadow: 1px 3px 15px -8px rgba(0,0,0,0.5); /* 버튼 입체 그림자 효과 */
border: 3px solid rgba(240,240,240,.75);
background-color: #f4f4f4;
margin: 5px;
cursor: pointer;
}
.numpad > div:active{ /* 누른 버튼 입체감 토글 */
box-shadow: none;
}
.numpad > div > span{
position: absolute;
display: block;
/* 버튼 텍스트 가운데 정렬 */
top: 45%;
left: 50%;
transform: translate(-50%,-50%);
}
/* 버튼 종류별 색상 */
.numpad > div.operator{
background-color: #f0dbef;
}
.numpad > div.allclear{
background-color: #dbdef0;
}
.numpad > div.calc{
background-color: #d0dec9;
}
.numpad > div:nth-child(4n+1){/* 한 행에 4개씩 버튼 표시 */
clear: left;
}
2. 계산기 입력창 구현
입력 숫자와 연산자가 오른쪽 정렬되어 표시되는 단순한 텍스트 출력창입니다.
보기 좋게 입체감이 나는 CSS로 장식을 더하고, 구글 웹 폰트로 비트맵 글자가 출력되도록 했습니다.
.pane{
font-family: DotGothic16;
font-size: 2em;
width: 290px;
height: 2em;
padding: 0.25em;
margin-bottom: .5em;
box-sizing: border-box;
text-align: right;
border-radius: .5em;
letter-spacing: 3px;
background-color: #abbda7;
box-shadow: inset 2px 2px 3px 0px rgba(0,0,0,.25);
}
표시 내용은 자바스크립트로 제어를 하며, bufferData 변수에 눌린 버튼 내용을 누적해서 보관하고 있고, 이 변수의 값을 입력창에 그대로 표시합니다.
3. 버튼 클릭 이벤트 처리
bufferData 변수에는 사용자가 입력한 계산식 내용이 누적되어 저장됩니다.
누적된 계산식은 Function() 생성자를 이용해 동적으로 실행하는 함수로 생성하게 됩니다. Function() 생성자는 아래 부분에서 자세히 설명합니다.
이벤트 핸들러는 넘버 패드 버튼들을 감싸고 있는 래퍼인 "numpad" 클래스에 정의합니다.
그래야 이벤트 핸들러 한 개로 넘버 패드에서 눌리는 모든 버튼을 핸들링 할 수 있습니다.
눌린 버튼의 텍스트(e.target.innerText)로 눌린 버튼이 어떤 것인지 식별할 수 있기 때문에 별도로 HTML 태그에 속성 값을 추가해서 자바스크립트에서 접근하는 복잡한 방식을 사용하지 않습니다.
눌린 넘버 패드 버튼들은 3가지로 분류됩니다.
AC | All Clear. 버퍼와 표시창의 표시 내용 모두 초기화 |
= | 버퍼의 누적 내용을 함수로 Function() 생성자로 계산해서 결과를 표시창에 표시하고 버퍼 초기화(반드시 버퍼 초기화를 나중에 해야 함) |
숫자,+-*/ | 눌린 버튼 텍스트를 버퍼에 누적하고 표시창에 누적 내용 표시 |
구조가 단순하기 때문에 switch 문으로 간단하게 분기를 해서 처리하면 됩니다. 계산식 결과를 얻기 위해 "="을 누르면 계산 결과를 얻어 화면에 표시한 후에 버퍼를 초기화해야 합니다.
let bufferData = '';
document.addEventListener('DOMContentLoaded', ()=>{
document.querySelector('.numpad').addEventListener('mousedown',(e)=>{
console.log(e.target.tagName + e.target.innerText);
switch(e.target.innerText){
case "AC":
//초기화
bufferData = '';
document.querySelector('.pane').innerText = '0';
break;
case "=":
//계산 결과를 표시하고 버퍼 초기화(초기화를 후에 해야 함)
document.querySelector('.pane').innerText = calc(bufferData);
bufferData = ''
break;
default:
//버퍼에 입력 숫자와 연산자 누적
if(!(bufferData == '' && e.target.innerText == '0')){
bufferData += ''+e.target.innerText;
document.querySelector('.pane').innerText = bufferData;
}
break;
}
})
})
4. Function() 생성자로 계산 결과 얻기
Function() 생성자는 동적으로 함수를 생성하는 객체입니다. 함수 실행 코드를 문자열 인자로 받아서 함수 실행 코드를 생성하기 때문에 코드 중간에 원하는 코드를 실행하는 함수를 만들어서 사용할 수 있습니다.
초간단 계산기 프로그램에서는 사용자가 입력한 사칙연산 계산식을 Function() 생성자 함수 실행 코드로 생성해서 함수를 실행하면 계산식 결과 값이 나오도록 하기 위해 사용합니다.
초간단 계산기에서는 함수를 동적으로 생성해서 재사용하는 것이 아니라 일회용이기 때문에 계산식의 결과값만 알면 됩니다. 따라서 즉시 실행 함수로 실행해서 결과 값만 반환받고 동적으로 생성한 함수를 소멸합니다.
//Function() 생성자로 계산식을 동적 함수로 생성한 후 즉시 실행한 결과를 반환함.
function calc(fomula){
return new Function('return '+fomula)()
}