JS 로 계산기 만들기

지현·2023년 6월 19일
2

Javascript / TypeScript

목록 보기
11/16
post-thumbnail

자바스크립트 연습 겸 하여 사칙연산 계산기를 만들어보았다. 처음에는 간단할 거라 생각했지만 생각보다 고려해야할 점이 많았다.

복잡한 계산은 아니지만 사칙연산 기능은 문제없이 작동된다.

🧱 HTML

버튼을 이렇게 일일이 만드는 방법 뿐인가 고민을 했지만 당장 생각나는 방안이 없어 그냥 16개의 버튼을 다 만들었다. 연산자는 operator , 숫자는 numBtn, 초기화는 ac, 결과는 result 라는 클래스를 각각 달아주어 조작했다.

<body>
    <div class='wrap'>
        <div class='display'>
            <div class='input'></div>
        </div>
        <div class='buttons'>
            <button data-type="ac" class='ac'>C</button>
            <button data-type='operator' class='operator'>+</button>
            <button data-type='operator' class='operator'>-</button>
            <button data-type='operator' class='operator'>x</button>
            <button class='numBtn'>7</button>
            <button class='numBtn'>8</button>
            <button class='numBtn'>9</button>
            <button data-type='operator' class='operator'>/</button>
            <button class='numBtn'>4</button>
            <button class='numBtn'>5</button>
            <button class='numBtn'>6</button>
            <button data-type='result' class='result'>=</button>
            <button class='numBtn'>1</button>
            <button class='numBtn'>2</button>
            <button class='numBtn'>3</button>
            <button class='numBtn'>0</button>
        </div>
    </div>
</body>

🎨Style

이유는 모르겠는데 다른 계산기를 만든 분들이 아이폰 기본 계산기의 색감을 따르고 있길래 나도 그렇게 만들어보았다. 사실 디자인적으로 큰 고민은 하지 않은 것 같😅

.wrap {
  margin: 100px auto;
  width: 300px;
  height: 400px;
  border: 1px solid transparent;
  background-color: rgb(151, 151, 151);
  border-radius: 5px;
}
.input {
  height: 20px;
  text-align: right;
}
.display {
  display: flex;
  flex-direction: column;
  height: 50px;
  font-size: 36px;
  font-weight: 700;
  border: 1px solid #777676;
  margin: 5px 5px 0 5px;
  padding: 10px;
  border-radius: 5px;
  background-color: #777676;
  color: #fff;
}
.buttons {
  padding: 5px;
  display: grid;
  height: calc(100% - 85px);
  gap: 5px;
  grid-template-columns: repeat(4, 1fr);
}
button {
  color: #fff;
  font-size: 36px;
  border: none;
  border-radius: 5px;
  cursor: pointer;
}
.numBtn {
  background-color: #828284;
}
.operator,
.result,
.ac {
  background-color: orange;
}

💪 JS

  • 기본적인 계산 기능은 calculate 함수를 만들었다. switch문을 이용하여 각 연산자 버튼을 눌렀을 때 인자로 받은 첫번째 수와 두번째 수를 계산해준다.
  • operatorOn , previoustNum , resentNum 은 각각 연산자를 입력했는지, 이전값인지 직전값인지 판별해주는 변수이다. (연속해서 계속 계산할 수 있도록 연산자를 누른 순간 방금까지 display에 있던 숫자가 previousNum이 된다)
const buttons = document.querySelectorAll('button');
const operators = document.querySelectorAll('.operator');
const displayElement = document.querySelector('.input');
const numBtn = document.querySelectorAll('.numBtn');

let operatorOn = ''; // 연산자 입력
let previousNum = ''; //이전 값
let resentNum = ''; // 최근값

//calculate 함수 (previousNum, operatorOn, resentNum 인자로 받음)
let calculate = (n1, operator, n2) => {
  let result = 0;
  switch (operator) {
    case '+':
      result = Number(n1) + Number(n2);
      break;
    case '-':
      result = Number(n1) - Number(n2);
      break;
    case 'x':
      result = Number(n1) * Number(n2);
      break;
    case '/':
      result = Number(n1) / Number(n2);
      break;
    default:
      break;
  }
  return String(result);
};
  • 첫번째 자리에 0이 오면 안되기 때문에 isFirstDigit 변수를 만들어 판별한다. 023 이런거 안되게...
  • 클릭한 버튼의 클래스를 action 이라는 변수로 두어 어떤 버튼을 클릭했는지 판별한다.
  • 그 이후에는 각각의 상황에 따라 조건을 부여하여 계산한다. 자세한 조건은 코드 내 주석 참고
let calculator = () => {
  let isFirstDigit = true; // 첫 번째 숫자 여부를 판별하는 변수

  buttons.forEach((item) => {
    item.addEventListener('click', (e) => {
      let action = e.target.classList[0];
      let click = e.target.innerHTML;

      if (action === 'operator') {
        //연산자 눌렀을 때
        operatorOn = click;
        previousNum = displayElement.textContent;
        displayElement.textContent = '';
        isFirstDigit = true; 
        // 연산자를 누르면 다음 숫자는 첫 번째 숫자가 됨
      }
      if (action === 'numBtn') {
        if (isFirstDigit && click === '0') {
          // 첫 번째 숫자이고 입력된 값이 0인 경우 아무 작업도 수행하지 않음
          return;
        }

        if (displayElement.textContent === '' && operatorOn === '') {
          //창이비어있고 연산자 누르지 않았을때(한자리)
          displayElement.textContent = click;
          previousNum = displayElement.textContent;
        } else if (
          //창이비어지 않고 연산자 누르지 않았을때(한자리이상)
          displayElement.textContent !== '' &&
          operatorOn === ''
        ) {
          displayElement.textContent = 
          displayElement.textContent + click;
          previousNum = displayElement.textContent;
        } else if (
          //창이비어있고 연산자 눌렀을때(한자리)
          displayElement.textContent === '' &&
          operatorOn !== ''
        ) {
          displayElement.textContent = click;
          resentNum = displayElement.textContent;
        } else if (
          //창이비어있지않고 연산자 누르지 않았을때 (한자리이상)
          displayElement.textContent !== '' &&
          operatorOn !== ''
        ) {
          displayElement.textContent = 
          displayElement.textContent + click;
          resentNum = displayElement.textContent;
        }
        isFirstDigit = false; 
        // 첫 번째 숫자 입력 후에는 첫 번째 숫자가 아님을 표시
      }

      if (action === 'result') {
        // = 눌렀을 때 calculate함수 실행
        displayElement.textContent = calculate(
          previousNum,
          operatorOn,
          resentNum
        );
        isFirstDigit = true; 
        // 결과를 표시한 후에는 다음 숫자는 첫 번째 숫자가 됨
      }
      if (action === 'ac') {
        //C 버튼 눌렀을 때 모든 할당 초기화
        displayElement.textContent = '';
        previousNum = '';
        operatorOn = '';
        resentNum = '';
        isFirstDigit = true; 
        // 모든 할당 초기화 후에는 다음 숫자는 첫 번째 숫자가 됨
      }
    });
  });
};
calculator();

마무리 & 고민

  • 모든 코드에 displayElement.textContent 를 일일이 입력하는게 너무 지저분해보여서 변수로 할당하고 싶었는데 변수에 넣으면 값이 바뀌지 않는다.. 이를 해결하기 위해 찾아보니 따로 displayElement.textContent를 해주는 함수를 만들라고 하는데 그럼 쓸 때 마다 그 함수를 호출하나 저걸 쓰나 거기서거기 아닌가..? 하는 생각이 들어 보류중이다.
function a(value) {
    let content = displayElement.textContent
    content = value
    return content
 }

이런식이나

const getDisplayValue = () => displayElement.textContent;

이런식으로 해보라는 조언을 받았는데 이렇게 해서 함수로 쓰면 정말 코드가 덜 지저분해지는게 맞나요..? 아직 잘 모르겠다ㅠ

뭔가 다른 분들은 더 기깔나게 만든 사람이 많은 것 같아 아직도 갈 길이 멀다는 생각이 든다. 하지만 하나의 어플리케이션 결과물을 만든 것도 오랜만이기에 블로그에 글을 써보았다. 다음엔 또 어떤 걸 만들까? 무언가 만들면서 공부하는게 제일 재밌는 것 같다..~

0개의 댓글