[TIL]계산기 리팩토링

yeols·2023년 10월 17일
1

[TIL]

목록 보기
18/72


이전 버전


html

<!doctype html>
<html lang="ko">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Calculator</title>
    <!--fonts-->
    <link rel="preconnect" href="https://fonts.googleapis.com" />
    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
    <link
      href="https://fonts.googleapis.com/css2?family=Gugi&display=swap"
      rel="stylesheet"
    />

    <link rel="stylesheet" href="css/styles.css" />
  </head>
  <body>
    <section class="app-container">
      <header class="app-header">
        <h1>Calculator Refactoring</h1>
      </header>
      <main class="app-main">
        <div class="div-result">
          <p id="result" class="result">0</p>
          <input type="hidden" id="current_type" value="0" />
        </div>
        <button class="button one" value="1"><span>1</span></button>
        <button class="button two" value="2"><span>2</span></button>
        <button class="button three" value="3"><span>3</span></button>
        <button class="button four" value="4"><span>4</span></button>
        <button class="button five" value="5"><span>5</span></button>
        <button class="button six" value="6"><span>6</span></button>
        <button class="button seven" value="7"><span>7</span></button>
        <button class="button eight" value="8"><span>8</span></button>
        <button class="button nine" value="9"><span>9</span></button>
        <button class="button zero" value="0"><span>0</span></button>
        <button class="operator add" value="+"><span>+</span></button>
        <button class="operator minus" value="-"><span>-</span></button>
        <button class="operator division" value="/"><span>/</span></button>
        <button class="operator multiply" value="X"><span>X</span></button>
        <button class="operator equal" value="="><span>=</span></button>
        <button class="button dot" value="."><span>.</span></button>
        <button class="operator clear" value="clear"><span>clear</span></button>
        <button class="operator delete" value="delete"></button>
      </main>
    </section>

    <script src="js/app.js"></script>
  </body>
</html>

이전 버전에서는 무지성으로 버튼을 div를 만들었고 현재 버전에서는 용도에 맞게 button으로 변경하였다.
css는 class를 button과 operator로 사용하여 바뀐게 없기때문에 생략한다.


js

// 항상 입력받는 배열
let currentNumArr = ["0"];
// 연산자가 입력되면 nextNumArr에 값을 받아오는 배열
let prevNumArr = ["0"];
// 항상 결과값만 갖는 배열
let resultNumArr = ["0"];
// 연산자를 받는 변수
let operator = "";

// 숫자버튼 button event
const numBtns = document.querySelectorAll(".button");
numBtns.forEach((btn) => {
  btn.addEventListener("click", (event) => {
    event.preventDefault();
    const {
      currentTarget: { value },
    } = event;

    // 배열에 이미 '.'이 있고 value가 '.' 이면 아무 행동을하지 않고 종료.
    if (currentNumArr.includes(".") && value === ".") {
      return;
    }

    // 배열의 0번 index에 '0'이 있을때
    if (currentNumArr[0] === "0") {
      // 배열에 '.'이 없고 입력값이 '.'이 아닐때
      if (!currentNumArr.includes(".") && value !== ".") {
        removeZero(currentNumArr);
      }
    }
    pushNum(currentNumArr, value);
  });
});

// 연산자 버튼 button event
const operatorBtns = document.querySelectorAll(".operator");
operatorBtns.forEach((btn) => {
  btn.addEventListener("click", (event) => {
    event.preventDefault();
    const {
      currentTarget: { value },
    } = event;

    // 입력 받은 연산자가 delete일 때
    if (value === "delete") {
      popNum(currentNumArr);
      return;
    }

    // 입력 받은 연산자가 clear일때
    if (value === "clear") {
      prevNumArr = ["0"];
      currentNumArr = ["0"];
      resultNumArr = ["0"];
      printNum(currentNumArr);
      operator = "";
      return;
    }

    // 연산자 버튼이 'delete', 'clear'가 아닌 value가 들어왔을때
    // resultNumArr를 prevNumArr로 옮긴 후 resultNumArr 초기화
    // = 연산자가 입력되면 계산 시작 그게 아닐경우
    // resultNumArr의 요소를 prevNumArr로 할당 후 resultNumArr 초기화
    if (operator !== "") {
      // 연산자가 입력 되었을 때 currentNumArr의 마지막 인덱스가 '.' 이면 '.' 삭제
      if (currentNumArr[currentNumArr.length - 1] === ".") {
        popNum();
      }
      const result = calculation();
      resultNumArr = [...(result + "")];
      prevNumArr = [...resultNumArr];
      currentNumArr = ["0"];
      if (value === "=") {
        printNum(resultNumArr);
        return;
      }
    } else {
      prevNumArr = [...currentNumArr];
      resultNumArr = [...currentNumArr];
      currentNumArr = ["0"];
    }

    printNum(resultNumArr);
    operator = value !== "=" ? value : "";
  });
});

// 결과 및 입력 받은 숫자 출력 span
const result = document.querySelector("#result");

// 입력받은 숫자 출력 함수
const printNum = (numArr) => {
  result.innerText = numArr
    .join("")
    .replace(/\B(?<!\.\d*)(?=(\d{3})+(?!\d))/g, ",");
};

/**
 * 입력 받은 숫자 배열에 push 함수
 * @param numArr
 * @param num
 */
const pushNum = (numArr, num) => {
  numArr.push(num);
  printNum(numArr);
};

/**
 * 숫자 삭제 pop 함수
 * @param numArr
 */
const popNum = (numArr) => {
  numArr.pop();
  numArr.length <= 0 && pushNum(numArr, "0");
  printNum(numArr);
};

/**
 * 배열 제일 앞의 요소가 '0'일 때 삭제하는 함수
 * @param numArr
 */
const removeZero = (numArr) => {
  numArr.shift();
  printNum(numArr);
};

const calculation = () => {
  const prevNum = parseFloat(prevNumArr.join(""));
  const currentNum = parseFloat(currentNumArr.join(""));

  switch (operator) {
    case "+":
      return prevNum + currentNum;
    case "-":
      return prevNum - currentNum;
    case "X":
      return (
        (prevNum === 0 ? 1 : prevNum) * (currentNum === 0 ? 1 : currentNum)
      );
    case "/":
      return (
        (prevNum === 0 ? 1 : prevNum) / (currentNum === 0 ? 1 : currentNum)
      );
  }
};

이전 버전과 다른 점

숫자를 입력받는 부분을 문자열에서 배열로 변경하였다.
문자열 보다 첫번째 인덱스요소와 마지막 인덱스 요소를 컨트롤 하기가 용이하여 변경하게되었다.
배열 0번째 인덱스에 0이 존재하고 .이 아닌 숫자가 입력되면 0을 지울때 Array.prototype.shift()메서드를 사용하여 삭제가 가능하고, 숫자가 입력되면 Array.prototype.push()를 이용해 마지막 인덱스 뒤의 요소로 삽입이 가능하다. 마지막으로 마지막 delete 버튼이 입력되면 마지막 index 요소를 Array.prototype.pop()을 사용 하여 제거가 가능하기 때문에 배열로 사용하게 되었다.

연산자가 입력되면 currentNumArr에 있는 요소를 prevNumArr ...(spread) 문법으로 배열을 재 구성하고 currentNumArr는 초기화 후 새로입력되는 숫자를 받는다.

문자열을 사용하면 약간 불편한 점이 있는데 계산기 기본기능인 연산을 할 때 배열을 Array.prototype.join('') 메서드로 문자로 변환시키고 변환시킨 문자열을 parseFloat() 함수로 Number type으로 변환하는 과정이 필요하다.

하지만 전체적으로 입력받은 값을 컨트롤 하는데 배열이 편했다.

배우고 있는 다체로운 문법을 사용하지는 못했지만, 꾸준히 공부해서 전역 변수가 없는 계산기로 리팩토링을 해봐야겠다.
class를 사용하여 getter setter을 이용한 방법도 고려해봐야겠다. 다음 리팩토링에서는 좀 더 개선된 계산기를 만들어보겠다..!!!!!!!!!!!!!!

역시 개발 공부는 개발을 하면서 찾고 고민하는게 나에게는 가장 효율이 좋은거같다.

profile
흠..

0개의 댓글

관련 채용 정보