[CodeSoom] 1주차 과제2 회고

곽형조 (KCena)·2020년 6월 12일
0

간단한 계산기 만들기

이번 과제는 간단한 계산기를 만드는 과제이다.

무엇을 고민했는가?🤔

  • 숫자를 누르면 숫자가 이어져서 화면에 표시되려면 어떻게 해야 할까?
  • 계산은 어떤식으로 수행되어야 할까?
  • 연산자 선택에 따른 계산 과정에서 조건문을 어떻게 줄일 수 있을까?
  • 계산 결과를 보여주는 방법과 현재 누른 숫자를 보여주는 방법은 어떻게 나눠야 할까?

어떻게 해결했는가?🧐

숫자를 이어서 표시하기

숫자 버튼을 다양하게 누르면 실제 계산기처럼 n자리의 숫자를 표시할 수 있어야 한다. 이는 자바스크립트의 문자열에 + 연산이나 탬플릿 문자열을 사용하면 해결할 수 있지만, 계산해야 할 숫자이므로 타입이 숫자인 것이 좋다고 판단하였다.

const handleClickNumber = (showNumber, expression, number) => render({
  expression,
  showNumber: showNumber * 10 + number,
});

숫자를 클릭할 때 발생하는 이벤트를 정의한 함수이다. expression은 계산해야 할 식이 담겨있는 배열이고, showNumber는 현재 화면에 보여주고 있는 숫자, number는 방금 클릭해서 함수의 인자로 들어온 숫자이다.

showNumber에 10을 곱하고 방금 입력한 숫자를 더해주면 간단하게 해결 할 수 있다.

계산하기

내가 선택한 계산 방법은 연산자가 눌렸을 때 마지막으로 눌린 연산자를 제외한 데이터로 연산을 수행하는 것이다.

const handleClickOperator = (showNumber, expression, operator) => render({
  result: calculator([...expression, showNumber]),
  showNumber: 0,
  expression: operator === '=' ? [] : [...expression, showNumber, `${operator}`],
});

const calculator = (expression) => {
  const operators = expression.filter((value) => buttonOperators.includes(value));
  const numbers = expression.filter((value) => !buttonOperators.includes(value));
  
  return numbers.reduce((acc, value, index) => {
    if (operators[index - 1] === '+') {
      return parseFloat(acc) + Number(value);
    }
    if (operators[index - 1] === '-') {
      return parseFloat(acc) - Number(value);
    }
    if (operators[index - 1] === '*') {
      return parseFloat(acc) * Number(value);
    }
    if (operators[index - 1] === '/') {
      return parseFloat(acc) / Number(value);
    }
    return acc;
  });

연산자가 눌렸을 경우에만 showNumber와 현재 연산자를 expression 배열에 담고 있다. 계산 결과를 구할 때는 마지막으로 눌린 연산자를 제외한 [...expression, showNumber]배열을 전달하여 calculator에서 계산이 수행된다.

예를들면 ['4', '+', '5'] 순서로 눌렸다면 ['4', '+']만이 calculator 함수에 전달된다. 함수 내부에서 숫자와 연산자를 따로 분리하여 숫자 배열에 reduce를 적용하여 계산이 진행된다.

acc에 초기값을 설정하지 않았으므로 4가 될 것이고, index는 1부터 시작하여 operator[index-1]operators 배열의 첫 번째 연산자부터 계산이 적용된다.

조건문 없이 계산하기

계산은 문제없이 되는 듯 하지만, if문을 나열하여 reduce가 수행되고 있다. 이 부분은 자바스크립트 객체의 key-value 특성을 이용하면 깔끔하게 해결할 수 있다.

const plus = (x, y) => parseFloat(x) + Number(y);
const minus = (x, y) => parseFloat(x) - Number(y);
const multiply = (x, y) => parseFloat(x) * Number(y);
const divide = (x, y) => parseFloat(x) / Number(y);

const calculator = {
  '+': plus,
  '-': minus,
  '*': multiply,
  '/': divide,
};

const calculation = (operator, x, y) => calculator[operator](x, y);

const getResult = (array) => {
  const operators = array.filter((value) => buttonOperators.includes(value));
  const numbers = array.filter((value) => !buttonOperators.includes(value));
  return numbers.reduce((acc, number, i) => (calculation(operators[i - 1], acc, number)));
};
  • reduce 내부에서 calculator[operators[i-1]](acc, number) 와 같이 쓸 수 있지만 Extract Function 리팩토링을 적용하여 calculation 함수로 뺐다.
  • 함수의 파라미터가 들어오는 순서와 사용되는 순서를 지켜주자.
  • Arrow function은 호출하자마자 바로 무언가를 반환하는 경우 한 줄로 작성할 수 있다. 그렇기에 반환값이 없을 경우 간략화를 생략하고 의도를 더 드러내자.

현재 누른 숫자 또는 계산 결과 보이기

한 자리에 보여주어야 하는 숫자는 두개이다. 연산자를 눌러 계산이 완료된 숫자를 보여주거나, 현재 누르고 있는 숫자를 보여주어야 한다. 이 부분은 논리 연산자를 유용하게 사용하면 간단하다.

function render({ result, showNumber, expression }) {
  const element = (
    <div>
      <p>간단 계산기</p>
      <div id="result">{result || showNumber}</div>
      <p id="button-list">
		...

render 함수 내부에서 result || showNumber 에 해당하는 부분이다. 정리하자면,

A || B 는 만약 A 가 Truthy 할경우 결과는 A 가 됩니다. 반면, A 가 Falsy 하다면 결과는 B 가 됩니다.

이 부분은 단축 평가 논리 계산법을 참고하자.

0개의 댓글