[렛츠기릿 자바스크립트] 계산기 만들기

EOH·2023년 5월 21일
0
post-thumbnail

💻 실습환경

vscode로 코드를 작성하고 chrome 웹 브라우저와 개발자도구를 이용해 코드를 실행해보았다.

💬 계산기 만들기

아주 간단한 계산만 할 수 있는 계산기를 만들어보았다. 피연산자 2개에 대해 + - * / 계산이 가능하다.


🔎 순서도


어떤 이벤트가 일어났을 때 각 이벤트에 따라 상황을 판단을 하고 함수를 실행하도록 순서도를 짜야한다.

1️⃣ 고차함수(Higher order function)으로 중복제거하기 ⭐️

코드를 짤 때는 반복되는 부분을 제거해서 더 효율적인 코드를 짤 수 있다. 계산기의 숫자 버튼을 누르면 해당 숫자가 찍히도록 하는 코드를 생각해보면

document.querySelector('#num-0').addEventListener('click', () => {
  if (operator) {
  	numTwo += '0';
  } else {
  	numOne += '0';
  }
  $result.value += '0'; //화면에 값을 표시해주는 코드
};

이런 식으로 0부터 9까지 다 적어줘야한다. 하지만 같은 코드에서 어떤 숫자가 찍히는지만 달라지기 때문에 이 값을 매개변수에 넣어주면 된다.

const onClickNumber = (number) => {
  if (operator) {
  	numTwo += number;
  } else {
  	numOne += number;
  }
  $result.value += number;
};
document.querySelector('#num-0').addEventListener('click', onClickNumber(0));

이렇게만 해도 중복이 많이 제거가 된다. 여기서 한 가지 주의할 점은 이벤트리스너의 리스너 함수 자리에 onClickNumber()를 넣으면 함수가 아닌 이 함수의 반환값이 들어오게 된다. 즉 현재 콜백함수의 반환값이 없으므로 undefined를 반환하는데 이는 'click' 이벤트가 발생하면 undefined를 실행하라는 뜻이므로 에러를 발생시킨다. 이를 방지하려면

const onClickNumber = (number) => {
  if (operator) {
  	numTwo += number;
  } else {
  	numOne += number;
  }
  $result.value += number;
  return () => {
  
  };
};
document.querySelector('#num-0').addEventListener('click', onClickNumber(0));

콜백함수가 함수를 반환하게끔 만들어주면 된다. 하지만 일단 자리만 맞춰준 것 뿐이지 이대로 실행을하면 return하는 함수 안에 아무 실행도 들어있지 않기 때문에 아무 일도 일어나지 않는다.

const onClickNumber = (number) => {
  return () => {
      if (operator) {
  		numTwo += number;
  	} else {
  		numOne += number;
  	}
  	$result.value += number;
  };
};
document.querySelector('#num-0').addEventListener('click', onClickNumber(0));

이렇게 return안에 함수의 동작까지 넣어줘야 제대로 작동이 된다.
또 중괄호와 return이 붙으면 생략이 가능해진다.

const onClickNumber = (number) => () => {
    if (operator) {
  		numTwo += number;
  	} else {
  		numOne += number;
  	}
  	$result.value += number;
  };
};
document.querySelector('#num-0').addEventListener('click', onClickNumber(0));

화살표가 연달아나오는 함수가 함수를 리턴하는 모양으로 줄일 수 있다. 이렇게 함수를 매개변수로 사용하거나 함수를 반환하는 함수를 고차함수라고 한다.

2️⃣ 이벤트 객체로 중복제거하기

위에서 고차함수를 이용해서 줄인 함수에서 두번째 함수의 매개변수로 event객체가 들어간다. 이 event객체는 브라우저가 넣어주는 것이다.

const onClickNumber = (number) => (event) => {
    if (operator) {
  		numTwo += number;
  	} else {
  		numOne += number;
  	}
  	$result.value += number;
  };
};
document.querySelector('#num-0').addEventListener('click', onClickNumber(0));

event객체를 받기 때문에 고차함수를 쓰지 않고 event.target.textContent를 이용해서 입력할 수도 있다.

const onClickNumber = (event) => {
    if (operator) {
  		numTwo += event.target.textContent;
  	} else {
  		numOne += event.target.textContent;
  	}
  	$result.value += event.target.textContent;
  };
};
document.querySelector('#num-0').addEventListener('click', onClickNumber);

즉 내가 event객체를 가져오면 클릭한 버튼의 글자를 그대로 가져올 수 있다.

3️⃣ c버튼을 눌렀을 때 초기화 하기

계산기에서 c버튼을 누르면 입력한 값이 지워질 뿐 만 아니라 입력받았던 변수들(numOne, numTwo, operator)도 초기화되어야한다.

document.querySelector('#clear').addEventListener('click', () => {
		numOne = '';
		operator = '';
		numTwo = '';
		$operator.value = '';
		$result.value = ''; //이건 화면만 초기화

clear클래스의 버튼을 누르면 안에 내용들이 실행되는 것이다. 이전 과제인 끝말잇기에서는 화면만 초기화하면 되었다. 하지만 이번에는 변수들에 저장된 값도 다 빈 문자열 ''로 초기화 해주어야한다는 것을 기억해야한다.

📝 전체 코드

<!DOCTYPE html>
<head>
	<meta charset="UTF-8">
	<title>계산기</title>
	<style>
		* { box-sizing: border-box }
		#result { width: 180px; height: 50px; text-align: right }
		#operator { width: 50px; height: 50px; margin: 5px; text-align: center }
		button { width: 50px; height: 50px; margin: 5px}
	</style>
</head>

<!--계산기 버튼 구현-->
<body>
	<input readonly id="operator">
	<input readonly type="number" id="result">
	<div class="row">
		<button id="num-7">7</button>
		<button id="num-8">7</button>
		<button id="num-9">7</button>
		<button id="plus">+</button>
	</div>
	<div class="row">
		<button id="num-4">4</button>
		<button id="num-5">5</button>
		<button id="num-6">6</button>
		<button id="minus">-</button>
	</div>
	<div class="row">
		<button id="num-1">1</button>
		<button id="num-2">2</button>
		<button id="num-3">3</button>
		<button id="divide">/</button>
	</div>
	<div class="row">
		<button id="clear">C</button>
		<button id="num-0">0</button>
		<button id="calculate">=</button>
		<button id="multiply">x</button>
	</div>
<script>
	let numOne = '';
	let operator = '';
	let numTwo = '';
	const $operator  = document.querySelector('#operator');
	const $result = document.querySelector('#result');

	const onClickNumber = (event) => {
		if (!operator) {
			numOne += event.target.textContent;
			$result.value += event.target.textContent;
			return;
		}
		if (!numTwo) {
			$result.value = '';
		}
		numTwo += event.target.textContent;
		$result.value += event.target.textContent;
	}; //중첩 if문 제거 후 코드

	document.querySelector('#num-0').addEventListener('click', onClickNumber);
	document.querySelector('#num-1').addEventListener('click', onClickNumber);
	document.querySelector('#num-2').addEventListener('click', onClickNumber);
	document.querySelector('#num-3').addEventListener('click', onClickNumber);
	document.querySelector('#num-4').addEventListener('click', onClickNumber);
	document.querySelector('#num-5').addEventListener('click', onClickNumber);
	document.querySelector('#num-6').addEventListener('click', onClickNumber);
	document.querySelector('#num-7').addEventListener('click', onClickNumber);
	document.querySelector('#num-8').addEventListener('click', onClickNumber);
	document.querySelector('#num-9').addEventListener('click', onClickNumber);
	//이벤트 객체를 이용해 코드 중복을 제거했다.
	
	const onClickOperator = (op) => () => {
		if (numOne) {
			operator = op;
			$operator.value = op;
		} else {
			alert('숫자를 먼저 입력하세요');
		}
	}

	document.querySelector('#plus').addEventListener('click', onClickOperator('+'));
	document.querySelector('#minus').addEventListener('click', onClickOperator('-'));
	document.querySelector('#divide').addEventListener('click', onClickOperator('/'));
	document.querySelector('#multiply').addEventListener('click', onClickOperator('*'));
	document.querySelector('#calculate').addEventListener('click', () => {
		if (numTwo) {
			switch (operator) {
				case '+':
					$result.value = parseInt(numOne) + parseInt(numTwo);
					break;
				case '-':
					$result.value = numOne - numTwo;
					break;
				case '*':
					$result.value = numOne * numTwo;
					break;
				case '/':
					$result.value = numOne / numTwo;
					break;
				default:
					break;
				}
		} else {
			alert('숫자를 먼저 입력하세요.');
		}
	});
	document.querySelector('#clear').addEventListener('click', () => {
		numOne = '';
		operator = '';
		numTwo = '';
		$operator.value = '';
		$result.value = ''; //이건 화면만 초기화
		//초기상태가 뭔지 알기 위해서는 초기상태 (let으로 선언한 변수)들을 한군데 몰아넣는게 좋다.
	});
</script>
</body>
</html>

💡 추가 과제: 이어지는 계산기 만들기

현재 내가 만든 계산기는 1번만 연산이 가능하다. 피연산자가 3개 이상인 연산은 하지 못한다. 이 연산을 가능하도록 만들어보는 것이 추가 과제이다. 아직 구현해보지 못했지만
=을 눌렀을 때 값을 어떤 변수에 저장하고, 이 변수에 값이 들어있으면 숫자가 아닌 연산자를 바로 받아서 이 변수의 값과 연산하도록 만들면 될 것같다.

📚 github & reference

my깃허브
렛츠기릿 자바스크립트 강의

profile
에-오

0개의 댓글