프로그래밍 공부하기

JS / 계산기 본문

Project/Practice

JS / 계산기

ihl 2020. 12. 17. 12:37

HTML+CSS+Javascript로 계산기 만들기 프로젝트를 수행했으므로 어떻게 만들었는지 주요 내용들을 정리해보려 한다.

내가 만든 계산기

CSS

1. 버튼에 마우스를 올리면 색상 바꾸기

.button__row > button:hover {
  background-color: #FFB2F5;
}

.button__row > button:active {
  background-color: #ef7993;
}

2. 버튼 정중앙 정렬(ex. AC, Enter 버튼)

.clear__and__enter {
  display: flex;
  flex-direction: row;
  justify-content: center;
  align-items: center;
}

.clear__and__enter > button {
  border-radius: 10px;
}

Javascript

0. 주요 변수 설정
    - firstNum: 숫자(x+y에서 x)

    - intermediateOperator: 입력된 연산자(+-*/) 
    - previousKey: 전에 입력한 버튼 class(number, operator, decimal, clear, calculate)
    - previousNum: 숫자(x+y에서 y/Reference 코드) / 계산결과(내 코드)

    - secondNum: 숫자(x+y에서 y). Reference에는 없고 내 코드에서 새로 추가하였다.
    - firstNum을 빼고 기본값은 undefined 이다. (clear버튼 누르면 기본값으로 초기화된다)

    - Reference코드의 경우 firstNum도 기본값이 undefined이며 display.textContent = '0' 으로 화면을 초기화한다.

1. 숫자 연속으로 입력하기
분석)
  - (+-*/)를 기준으로 앞부분은 첫번째 숫자, 뒤는 두번째 숫자가 된다.
  - 처음에 계산기의 화면의 값은 0이다.
  - 0인 상태에서 0을 입력하면 화면에 입력되지 않고, 숫자를 입력하면 화면의 0이 입력한 숫자로 바뀐다.

  - 화면에 0이 아닌 숫자가 있는 경우 화면의 숫자 뒤에 숫자를 추가한다.

  - 직전에 연산자(+-*/) 입력 후 숫자를 입력하면 화면이 입력한 숫자로 변한다. 
처리)
  - 현재 계산기의 값이 0이거나 이전에 operator가 입력되었다면 새롭게 숫자를 입력하는 상태이다.
  - 그 외의 경우는 기존 값(string)에 새로 입력한 숫자(버튼)를 더한다.

if(display.textContent === '0' || previousKey === 'operator'){
	display.textContent = buttonContent;
}else{
	display.textContent += buttonContent;
}
previousKey = 'number';

 

2. 연산자를 누르면 누른 버튼의 색상이 바뀌고 숫자를 누르면 다시 돌아온다.(연산자는 계산기 화면에 표시되지 않는다)

처리)
  - 연산자를 누르면 해당 버튼에 isPressed라는 클래스 추가

    (<Button Class=operator isPressed...>로 만든다.)
  - css에서 isPressed 클래스 색상 변경
  - 숫자를 눌렀을 때 이전 누른 버튼이 연산자라면 해당 버튼의 isPressed 클래스를 제거한다.

   (<Button Class=operator..>로 만든다.)

  - 일단 여기서는 pressedOperator[0]만 isPressed를 제거했지만 사실 pressedOperator 배열의 요소 모두의 isPressed를  제거해주어야 한다.(Reference에서는 그렇게 한다)

  const target = event.target; 
  //...number 버튼을 누른 경우
  if(previousKey === 'operator'){
        let pressedOperator = document.getElementsByClassName('isPressed') 
        pressedOperator[0].classList.remove('isPressed');//일단 0번째 클래스만 제거
      }
  //...operator 버튼을 누른 경우
  //누른 버튼의 html 태그에 isPressed 클래스를 추가한다.
  target.classList.add('isPressed');

 

3. .7을 입력하면 0.7이 입력된다.

처리)
  - .(decimal)을 입력할 때 직전에 입력한 값이 숫자라면 화면에 .을 더하고 0이거나 연산자라면 0.을 더한다

if(previousKey === 'number' || display.textContent === '0'){
        display.textContent += buttonContent;
}else if(previousKey === 'operator'){
        display.textContent = '0' + buttonContent;
}

 

4. Enter를 누르면 이전 연산 수행

분석) 
  - 3, -, 3, enter, enter 입력 = 3-3-3 = -3
  - 연산자가 없는 상태에서 Enter를 누르면 동작X
  - 이전 연산값을 기억해야한다.

 

처리1(Reference))

 - Reference의 경우 firstNum을 undefined로 기본값을 가지므로 if(firstNum) 을 통해 숫자와 연산자가 입력되었는지 확인할 수 있다.

 - 처음 Enter를 누른 경우(else) 현재 계산기에 보이는 값(두번째 숫자)을 previousNum에 넣고 계산하여 화면에 결과를 보여준다.

 - 그 후 Enter를 눌렀다면 현재 계산기에 보이는 값과 두번째 숫자(previousNum)를 계산하여 화면에 보여준다.

 ex1. '10 - 3 Enter' 를 입력했다면 previousNum = 3, display.textContent = 7이 된다.

 ex2. ex1 후에 다시 'Enter'를 입력했다면 display.textContent = 7 - 3 = 4가 된다.

if (firstNum){
	if (previousKey === 'calculate') {
		display.textContent = calculate(display.textContent, intermediateOperator, previousNum);
	} else {
		previousNum = display.textContent;
		display.textContent = calculate(firstNum, intermediateOperator, display.textContent);
	}
}

 


처리2(내 방식))

  - 원리는 동일한데 previousNum의 의미가 다르고 secondNum이라는 변수를 추가하였다.
  - secondNum이라는 변수를 따로 만들어서 두번째 숫자를 저장한다.(Reference의 경우 두번째 숫자를 PreviousNum에 넣었다.)

  - PreviousNum에는 현재 계산기에 보여지는 숫자를 넣었다.

if (action === 'calculate') {
      if(intermediateOperator === undefined){
        return;
      }
      if(previousKey === 'calculate'){
        previousNum = calculate(previousNum, intermediateOperator, secondNum);
        display.textContent = previousNum;
      }else{
        secondNum = display.textContent;
        previousNum = calculate(firstNum, intermediateOperator, secondNum);
        display.textContent = previousNum;
      }
      previousKey = 'calculate';
    }

 

 

5. 다항식 처리

처리1(Reference))

 - 연산자 버튼을 눌렀는데 첫번째 숫자와 연산자가 이미 존재하는 경우 앞의 값을 계산해야 한다.

  - ex. '1+2'를 클릭한 상태에서 '-'를 클릭한 상황이라 볼 수 있다. 이 경우 1+2를 연산해주어서 화면에 표시해야함

 - 현재 입력된 연산자 앞의 값 앞의 값 혹은 앞의 값을 계산하여 firstNum으로 할당한다.

  - ex1. '1+2'를 클릭한 상태에서 '-'가 왔다면 앞의 1+2를 계산하여 firstNum으로 만든다.

  - ex2.  '1'을 입력한 상태에서 '+'가 왔다면 1을 firstNum으로 만든다.

//연산자 버튼을 눌렀다면...
if (firstNum && intermediateOperator && previousKey !== 'operator' && previousKey !== 'calculate') {
	display.textContent = calculate(firstNum, intermediateOperator, display.textContent);
}
firstNum = display.textContent;


처리2(내코드))
  - Reference와 원리는 동일한데 secondNum을 만들어서 이를 할당해주었다.

 //연산자 버튼 눌렀다면...
      if(firstNum !== undefined && intermediateOperator !== undefined && previousKey === 'number'){
        secondNum = display.textContent;
        firstNum = calculate(firstNum, intermediateOperator, secondNum);
        display.textContent = firstNum;
      }else{
        firstNum = display.textContent;
      }

 

6. 키보드로도 작동되게 한다.

처리)
  - 입력한 키에 알맞는 버튼 클릭 이벤트를 발생시킨다.
  - 숫자, 연산자의 경우 키가 여러개 이므로 일단 숫자인경우/연산자인경우로 나누고 그 안에서 다시 해당 입력에 해당하는 버튼을 찾는다.
  (키보드 9 > 숫자 > '9'버튼 클릭 이벤트)

window.addEventListener('keydown', function (event){
  const key = event.key;
  if(key >= '0' && key <= '9'){
    let classList = document.getElementsByClassName("number");
    for(let i=0; i < classList.length; i++){
      if(classList[i].textContent === key){
        classList[i].click();
        break;
      }
    }
  }else if(key == 'Enter'){
    document.getElementsByClassName("calculate")[0].click();
  }else if(key == 'Escape'){
    //....(생략)

 

previousNum이라는 변수의 의미를 착각해서 코드가 복잡해진 것 같다...ㅠㅠ previousNum이 무슨 뜻일지 먼저 집착하기 보단 어떻게 문제를 풀지 방법을 먼저 생각하고 previousNum을 적절히 끼워넣는 식으로 하는 것이 더 좋았을 것 같다.

'Project > Practice' 카테고리의 다른 글

TypeScript / Project Timer  (0) 2021.04.05
GraphQL / Tour Sight Search  (0) 2021.02.21
socket.io / 실시간 채팅  (0) 2021.02.09
JSAnimation / BrawlStars GunFight!  (0) 2021.01.18
DOM / Twittller  (0) 2020.12.30
Comments