이번 과제는 간단한 계산기를 만드는 과제이다.
숫자 버튼을 다양하게 누르면 실제 계산기처럼 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)));
};
calculator[operators[i-1]](acc, number)
와 같이 쓸 수 있지만 Extract Function 리팩토링을 적용하여 calculation
함수로 뺐다.한 자리에 보여주어야 하는 숫자는 두개이다. 연산자를 눌러 계산이 완료된 숫자를 보여주거나, 현재 누르고 있는 숫자를 보여주어야 한다. 이 부분은 논리 연산자를 유용하게 사용하면 간단하다.
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 가 됩니다.
이 부분은 단축 평가 논리 계산법을 참고하자.