계산기(Pair)
Sprint Review(Zoom)
Pair Review(Survey)
Sprint Feedback(Survey)
계산기 : 어제(4월 12일) 필수과제인 Bare Minimum Requirements를 완료하였기에, 오늘은 Advanced challenge과 Nightmare를 도전하였다.(Javascript로 기능을 조작) 또한 CSS와 Javascript로 약간의 재미적 요소를 넣어보았다.
1. Advanced challenge
Step1 - 숫자를 클릭하여 화면에 입력하기
- 어제의 이상한 계산기와는 달리 일반적인 계산기를 만들어 보는 것이다.
- 숫자 입력시 catenatioin이 되도록 구현한다.
- 연산자(operator)를 눌러도 첫번째 입력한 수는 화면에 그대로 출력된다.
- textContent를 활용한다.
Step2 - 연산자 버튼을 클릭하여 계산을 준비하기
- 변수 previousKey를 이용하여 이전에 클릭한 버튼이 숫자인지, 연산자인지 구분하여 코드를 작성.
- 연산자(operator)를 입력 후 두번째 수를 입력하면 두번째 수는 화면에 나타나고 첫번째 수는 변수에 담긴다.
- 입력된 연산자는 임의의 변수에 담긴다.
Step3 - Enter로 계산하고, AC로 초기화하기
- enter가 클릭되면 calculate함수에 의한 결과값이 계산기의 화면에 출력된다.
Step1- 숫자를 클릭하여 화면에 입력하기(단, 본인의 코드에는 night mare단계가 포함되어 있다.)
const display = document.querySelector('.calculator__display--for-advanced');
let firstNum, operatorForAdvanced, previousKey, previousNum;
buttons.addEventListener('click', function (event) {
const target = event.target;
const action = target.classList[0];
const buttonContent = target.textContent;
if (target.matches('button')) {
if (action === 'number') {
if(operatorForAdvanced !== undefined){ //연산자가 한번 선언되어 있다면
if(display.textContent === firstNum){ // 화면에 firstNum이 있다면(두번째 숫자의 첫번째가 나올 차례이기 때문에 화면이 다른 수로 채워져야한다.)
display.textContent = buttonContent; //화면에는 방금 누른 버튼이 출력되어라.
}else{
display.textContent = display.textContent + buttonContent; //두번째 수의 첫번째 혹은 여러수가 입력되었을때는 그 뒤에 방금 누른 버튼의 숫자(textContent)가 붙어라.
}
}else if(operatorForAdvanced === undefined && display.textContent === '0') { //연산자가 선언되지 않았고 화면에 0이라면(초기상태라면 즉 firstNum이 입력되야한다면)
//console.log('숫자 ' + buttonContent + ' 버튼');
display.textContent = buttonContent; // 화면에 나타날 텍스트를 버튼의 텍스트로 변경
}else if(operatorForAdvanced === undefined && display.textContent !== '0') { //firstNum의 첫번째 혹은 여러수가 입력되었을때는
display.textContent = display.textContent + buttonContent; //그 뒤에 방금 누른 버튼의 숫자(textContent)가 붙어라.
}
}
}
Step2 - 연산자 버튼을 클릭하여 계산을 준비하기(단, 본인의 코드에는 night mare단계가 포함되어 있다.)
const display = document.querySelector('.calculator__display--for-advanced');
let firstNum, operatorForAdvanced, previousKey, previousNum;
buttons.addEventListener('click', function (event) {
const target = event.target;
const action = target.classList[0];
const buttonContent = target.textContent;
if (target.matches('button')) {
if (action === 'operator') { //operator(연산자 버튼이 눌리면)
operatorForAdvanced = buttonContent; //calculate 버튼(enter)을 누를 시 계산을 위하여 현재 입력한 연산자를 변수에 할당.
firstNum = display.textContent; calculate 버튼(enter)을 누를 시 계산을 위하여 현재 화면에 있는 수를 변수에 할당.
//아래 코드는 나이트메어를 위해 치다가 시간이 만료되어 완성하지 못한 코드입니다. 아래에서 추가로 다룰예정
// if(operatorForAdvanced !== undefined){//두번 혹은 그 이상이라는 거지
// previousNum = calculate(result, operatorForAdvanced, display.textContent)//100 + 200에다가 +를 한 번 더 눌렀는 상황
// console.log(previousNum);
// }
//위 코드는 나이트메어를 위해 치다가 시간이 만료되어 완성하지 못한 코드입니다. 아래에서 추가로 다룰예정
}
}
Step3- Enter로 계산하고, AC로 초기화하기(단, 본인의 코드에는 night mare단계가 포함되어 있다.)
const display = document.querySelector('.calculator__display--for-advanced');
let firstNum, operatorForAdvanced, previousKey, previousNum;
buttons.addEventListener('click', function (event) {
const target = event.target;
const action = target.classList[0];
const buttonContent = target.textContent;
if (target.matches('button')) {
if (action === 'clear') {
display.textContent = '0';
//화면을 초기화한다.
operatorForAdvanced = undefined;
//연산자가 입력되어 할당된 operatorForAdvanced라는 변수를 undefined로 바꾸어 준다.
//! 적다보니 발견한것은 firstNum을 초기화해줘야하는데...빼먹었다. ^0^ 그런데 advanced challenge의 테스트 케이스를 통과하였다....이상하다..
}
if (action === 'calculate') {
display.textContent = calculate(firstNum, operatorForAdvanced, display.textContent)
}//입력된 값들을 바탕으로 calculate함수를 실행해주고 결과를 리턴하여 화면으로 출력해준다.
}
위 코드의 결과는 아래와 같다.
Step3의 코드의 주석에서 말했듯이 빼먹은 부분이 있었지만 다행히(?)도 advanced는 통과할 수 있었으나....
더 큰 산이 뒤에 있었으니.....nightmare.....
애초에 nightmare에는 설명이 없었다.
그러나 테스트케이스를 통과하기 위하여 하나하나씩 도전해가기 시작했다.
많은 시간을 pair와 조건문에 조건문을 넣고 그안에 또 조건문을 넣는 미친듯한 삽질을 했다.
그 결과 코드는 난잡하였으나 꽤나 많은 부분을 해결했는데 딱 두가지 부분이 막혀 더이상 진행을 못하였고
nightmare는 해결을 못한 채 CSS를 부랴부랴 수정하여 제출하였다.
reference를 받고 느낀것은 엄청난 감탄이었다. 간결하면서도 정확한 코드!
자, 아래 나이트메어 테스트케이스 결과를 보고 부족한 점은 무엇이었으며 어떻게 고치면 될지 알아보자 그리고 해결해보자
부족한 점
- calculate 버튼 누르기 전의 값이 무엇이냐에 따라 도출되는 값을 정의하지 못했음.
- 현재 클릭한 버튼이 어떤종류인지 결정하는 previousKey(이것으로 calculate가 연속으로 입력될 때 그리고 숫자 이후 입력될 때를 나누어서 상세하게 값을 도출해 낼 수 있음), n1 + operator + n2 + (enter할 차례에서) 현재 화면에 떠있는 값을 정의하는 previousNum(이것으로 enter가 한번만 눌러질때, 연속으로 눌러질때를 나누어서 상세하게 값을 도출해 낼 수 있음)을 정의하지 않아서 수없이 많은 중첩 조건문을 만들었어야 했음.
- 위 clear버튼을 눌렀을 경우에 리셋되야하는 값들이 추가되어야한다.(위 코드에서 말했듯이 firstNum은 물론이고 previousNum과 previousKey도 포함하여....)
위 부족한 점들을 고치기 전에 우선 레퍼런스와 레퍼런스에 대한 나의 리뷰를 보자.
function calculate(n1, operator, n2) {
let result = 0;
if (operator === '+') {
result = Number(n1) + Number(n2);
}
if (operator === '-') {
result = Number(n1) - Number(n2);
}
if (operator === '*') {
result = Number(n1) * Number(n2);
}
if (operator === '/') {
result = Number(n1) / Number(n2);
}
return String(result);
}
const display = document.querySelector('.calculator__display--for-advanced'); // calculator__display 엘리먼트와, 그 자식 엘리먼트의 정보를 모두 담고 있습니다.
let firstNum, operatorForAdvanced, previousKey, previousNum;
buttons.addEventListener('click', function (event) {
const target = event.target;
const action = target.classList[0];
const buttonContent = target.textContent;
const buttonContainerArray = buttons.children;
if (target.matches('button')) {
for (let i = 0; i < buttonContainerArray.length; i++) {
const childrenArray = buttonContainerArray[i].children;
for (let j = 0; j < childrenArray.length; j++) {
childrenArray[j].classList.remove('isPressed');
}
}
if (action === 'number') {
if (display.textContent === '0' || previousKey === 'operator' || previousKey === 'calculate') {
display.textContent = buttonContent;//직전에 누른 버튼이 연산자 이거나 계산키, 그리고 아무것도 입력되지않은 0일 경우에 지금 누른 숫자의 버튼이 처음 디스플레이에 찍히도록 한다.
} else {
display.textContent = display.textContent + buttonContent; //class가 number에 해당하는 버튼을 눌렀을 때 기존에 숫자가 있는 경우는 그 뒤에 붙여서 concatenation한다.
}
previousKey = 'number'; //방금 누른 키가 number이므로 previousKey로 셋팅한다.
}
if (action === 'operator') {
target.classList.add('isPressed');
if (firstNum && operatorForAdvanced && previousKey !== 'operator' && previousKey !== 'calculate') {
//첫번째 누른 숫자(operator 이전에 누른 숫자)와 연산자가 있으면 그리고 연산자를 연속으로 누른게아니라면 또한 결과 계산(enter) 후 연산자를 누른게 아니라면(그러니까 연산자 이후 number를 다시 눌렀다면)
display.textContent = calculate(firstNum, operatorForAdvanced, display.textContent);
//operator키를 누를 시 화면에 나타나는 값은 calculate함수에 의해 계산되는 문자열 타입의 리턴 값
}
firstNum = display.textContent; //처음 연산자를 누르면 firstNum은 연산자가 입려되기 전 화면에 있던 값이다.
//operator 이후에 다시 숫자를 넣으면 이전에 계산한 값들이 날아가고 display.textContext가 다시 정의 되므로 그전에 firstNum에 operator버튼을 눌러 계산한 값을 넣어준다.
//그리하여 다시 숫자 버튼이 눌러진 이후 연산자 버튼을 눌렀을 때 110번째 줄에 firstNum으로 들어가 현재화면의 있는 값과 다시 calculate함수에 들어가 값을 리턴하기를 반복할 것이다.
operatorForAdvanced = buttonContent; //operatorForAdvanced는 operator버튼을 처음 눌렀을 때 button의 textContent.
previousKey = 'operator';//방금 누른 키가 operator이므로 previousKey로 셋팅한다.
}
if (action === 'decimal') {
if (!display.textContent.includes('.') && previousKey !== 'operator') {
//소숫점은 숫자스트링에 하나만 들어갈 수 있기 때문에 화면에 '.'가 없다면 그리고 number버튼 혹은 calculate(enter)버튼을 눌렀다면(operator를 누른 직후가 아니라면)
display.textContent = display.textContent + '.';
//기존의 있던 숫자(이 숫자에는 .이 포함되어있지 않다.)뒤에 '.'을 붙여준다.
} else if (previousKey === 'operator') {
//연산자 버튼을 누른 후 '.'을 찍는다면
display.textContent = '0.';
//화면에는 '0.'이 표시된다.
}
previousKey = 'decimal';//방금 누른 키가 decimal이므로 previousKey로 셋팅한다.
}
if (action === 'clear') {
firstNum = undefined;
operatorForAdvanced = undefined;
previousNum = undefined;
previousKey = 'clear';
//어떠한 수나 연산자 기타 다른 버튼이 눌렸을 시 정의되어지는 값들을 초기화
display.textContent = '0';//방금 누른 키가 AC이므로 초기의 상태로 만들어준다.
}
if (action === 'calculate') {
if (firstNum) { //calculate(enter)버튼을 누른다는 것은 firstNum과 operator를 누른 후 firstNum과 연산해야하는 다른 수가 있다는 것을 가정하기에 firstNum이 있다면을 가정했다.
if (previousKey === 'calculate') {
//enter를 연속으로 누른 경우
display.textContent = calculate(display.textContent, operatorForAdvanced, previousNum);
//(n1 + operator + n2의 결과값) + operatorForAdvanced(직전에 계산한 연산자) + n2의 결과를 화면에 나타낸다.
} else {
//enter가 아닌 수를 이전에 누른 경우 n1 + operator + n2(숫자) + (enter할 차례)
previousNum = display.textContent;
//n2가 previousNum
display.textContent = calculate(firstNum, operatorForAdvanced, display.textContent);
//화면에 출력되는 값은 n1 + operator + n2의 결과값이다.
}
}
previousKey = 'calculate';//방금 누른 키가 calculate이므로 previousKey로 셋팅한다.
}
}
});
아아 얼마나 아름답고 효율적인 코드인가!
하지만 나의 코드가 부족할 지언정 위에 코드를 그대로 뺏기고 싶지는 않다. 물론 reference 코드도 공부 하며 나의 코드에 양분이 될 녀석들을
뽑아내기는 할 것이다.
나의 코드를 수정하여 오늘 nightmare를 완성시키기에는 많은 시간이 소요되므로 이번주 주말까지 완성 시켜 수정하도록 하겠다.
글을 마치기 전 오늘 제출한 계산기를 보고 고치고 싶은 점을 적어봄으로써 마무리하겠다.
고치고 싶은 점
- 커서와 손이 떨어져있다. (CSS에 transform translate(-50%, -50%)를 추가하겠다.)
- 커서를 없애고 싶다.
- 손그림이 화면에서 나갈 때 스크롤창이 생긴다.(overflow : hidden 하자.)
- 클릭할 때 손 모양이 바뀌게 해보자
나의 코드를 바탕으로 nightmare와 위 고치고 싶은 점을 해결해서 주말에 포스팅하겠다!
'코드스테이츠' 카테고리의 다른 글
2021년 4월 15일 코드스테이츠 DAY-11(Linux 기초, Git 기초) (0) | 2021.04.15 |
---|---|
2021년 4월 14일 코드스테이츠 DAY-10(Linux 기초) (0) | 2021.04.14 |
2021년 4월 12일 코드스테이츠 DAY-8(CSS + 계산기)#1 (0) | 2021.04.12 |
2021년 4월 9일 코드스테이츠 DAY-5(HTML)( + 일주일 솔직 후기) (0) | 2021.04.09 |
2021년 4월 8일 코드스테이츠 DAY-4(JS/Node)(Coplit)(pseudo code) (2) | 2021.04.08 |