코드스테이츠_2주차_수

윤뿔소·2022년 8월 31일
0

CodeStates

목록 보기
8/47

목업한 계산기를 이제 JS로 동작을 추가해 만들어보자!
근데 목업한 건 나중에 하고 코스에서 보내주는 코드에 추가하여 조건문, 반복문의 구조를 이용해 오류가 나는 부분들을

기본 코드

계산기 과제 레포지토리에 HTML, CSS, JS 뿐만 아니라 테스트 코드도 있으니 다운받아서 해보자

// calculator 엘리먼트와, 그 자식 엘리먼트의 정보를 모두 담고 있습니다.
const calculator = document.querySelector(".calculator");
// calculator__keys 엘리먼트와, 그 자식 엘리먼트의 정보를 모두 담고 있습니다.
const buttons = calculator.querySelector(".calculator__buttons"); 

// calculator__operend--left 엘리먼트와, 그 자식 엘리먼트의 정보를 모두 담고 있습니다.
const firstOperend = document.querySelector(".calculator__operend--left"); 
// calculator__operator 엘리먼트와, 그 자식 엘리먼트의 정보를 모두 담고 있습니다.
const operator = document.querySelector(".calculator__operator"); 
// calculator__operend--right 엘리먼트와, 그 자식 엘리먼트의 정보를 모두 담고 있습니다.
const secondOperend = document.querySelector(".calculator__operend--right"); 
// calculator__result 엘리먼트와, 그 자식 엘리먼트의 정보를 모두 담고 있습니다.
const calculatedResult = document.querySelector(".calculator__result"); 

function calculate(n1, operator, n2) {
  let result = 0;
  // TODO : n1과 n2를 operator에 따라 계산하는 함수를 만드세요.
  // ex) 입력값이 n1 : '1', operator : '+', n2 : '2' 인 경우, 3이 리턴됩니다.
  return String(result);
}

buttons.addEventListener("click", function (event) {
  // 버튼을 눌렀을 때 작동하는 함수입니다.

  const target = event.target; // 클릭된 HTML 엘리먼트의 정보가 저장되어 있습니다.
  const action = target.classList[0]; // 클릭된 HTML 엘리먼트에 클레스 정보를 가져옵니다.
  const buttonContent = target.textContent; // 클릭된 HTML 엘리먼트의 텍스트 정보를 가져옵니다.

// Bare Minimum Requirements
  if (target.matches("button")) {
    // TODO : 계산기가 작동할 수 있도록 아래 코드를 수정하세요.
    // 클릭된 HTML 엘리먼트가 button이면
    if (action === "number") {
      // 그리고 버튼의 클레스가 number이면
      // 아래 코드가 작동됩니다.
      console.log("숫자 " + buttonContent + " 버튼");
    }

    if (action === "operator") {
      console.log("연산자 " + buttonContent + " 버튼");
    }

    if (action === "decimal") {
      // console.log('소수점 버튼');
    }

    if (action === "clear") {
      console.log("초기화 버튼");
    }

    if (action === "calculate") {
      console.log("계산 버튼");
    }
  }
});
// Advanced Challenge test와 Nightmare test
// calculator__display 엘리먼트와, 그 자식 엘리먼트의 정보를 모두 담고 있습니다.
const display = document.querySelector(".calculator__display--for-advanced"); 
let firstNum, operatorForAdvanced, previousKey, previousNum;

buttons.addEventListener("click", function (event) {
  // 버튼을 눌렀을 때 작동하는 함수입니다.

  const target = event.target; // 클릭된 HTML 엘리먼트의 정보가 저장되어 있습니다.
  const action = target.classList[0]; // 클릭된 HTML 엘리먼트에 클레스 정보를 가져옵니다.
  const buttonContent = target.textContent; // 클릭된 HTML 엘리먼트의 텍스트 정보를 가져옵니다.
  // ! 위 코드는 수정하지 마세요.

  // ! 여기서부터 Advanced Challenge & Nightmare 과제룰 풀어주세요.
  if (target.matches("button")) {
    if (action === "number") {
    }
    if (action === "operator") {
    }
    if (action === "decimal") {
    }
    if (action === "clear") {
    }
    if (action === "calculate") {
    }
  }
});

Bare Minimum Requirements

의사코드

HTML 목업 이미지

1. 숫자, 연산자 버튼 : 숫자가 눌렸을 때 1번째에 입력될지 2번째에 입력될지 구분, 연산자를 눌렀고 그 후 숫자를 누르면 2번째에 입력됨
2. 엔터를 누르면 답이 나옴, 답이 나오기 위해 계산 함수도 작성
3. 초기화 버튼을 작성해 모든 변수가 처음으로 되돌아가도록 구현

JS 코드 작성

// 계산 함수
function calculate(n11, operator, n22) {
  // fO, sO 쓰면 안됨?
  let result = 0;
  n1 = Number(n11);
  n2 = Number(n22);
  // TODO : n1과 n2를 operator에 따라 계산하는 함수를 만드세요.
  // ex) 입력값이 n1 : '1', operator : '+', n2 : '2' 인 경우, 3이 리턴됩니다.
  if (operator === "+") {
    result = n1 + n2;
  } else if (operator === "-") {
    result = n1 - n2;
  } else if (operator === "*") {
    result = n1 * n2;
  } else if (operator === "/") {
    result = n1 / n2;
  }
  return String(result);
}
// yourStyle.css에서 36번 스타일을 토대로 작성한 코드(none처리)
// 버튼을 눌렀을 때 작동하는 함수
buttons.addEventListener("click", function (event) {
  const target = event.target; // 클릭된 HTML 엘리먼트의 정보가 저장되어 있습니다.
  const action = target.classList[0]; // 클릭된 HTML 엘리먼트에 클레스 정보를 가져옵니다.
  const buttonContent = target.textContent; // 클릭된 HTML 엘리먼트의 텍스트 정보를 가져옵니다.
  // ! 위 코드(Line 19 - 21)는 수정하지 마세요.
  if (target.matches("button")) {
    // 클릭된 HTML 엘리먼트가 button이면
    // TODO : 계산기가 작동할 수 있도록 아래 코드를 수정하세요. 작성되어 있는 조건문과 console.log를 활용하시면 쉽게 문제를 풀 수 있습니다.
    if (action === "number") {
      // 그리고 버튼의 클레스가 number이면
      // 아래 코드가 작동됩니다.
      console.log("숫자 " + buttonContent + " 버튼");
      if (firstOperend.textContent === "0") {
        // 왜 그냥 0이면 안됨..?
        firstOperend.textContent = buttonContent;
      } else if (firstOperend.textContent !== "0") {
        secondOperend.textContent = buttonContent;
      }
    }
    if (action === "operator") {
      console.log("연산자 " + buttonContent + " 버튼");
      operator.textContent = buttonContent;
    }
    // if (action === "decimal") {
    //  console.log('소수점 버튼');
    // }
    if (action === "clear") {
      console.log("초기화 버튼");
      firstOperend.textContent = 0;
      secondOperend.textContent = 0;
      operator.textContent = "+";
      calculatedResult.textContent = 0;
    }
    if (action === "calculate") {
      calculatedResult.textContent = calculate(firstOperend.textContent, operator.textContent, secondOperend.textContent);
      console.log("계산 버튼 " + calculatedResult.textContent);
    }
  }
});

Advanced Challenges, Nightmare

  • Advanced Challenges는 사용자의 의식 흐름 상 사용할 수 있게끔 User Flow를 바탕으로 만듦
  • Nightmare는 계산기를 사용할 시 생기는 대부분의 오류를 없애주는 작업을 해 도전하는 항목임1. CSS 클래스를 JS로 제어해 hoveractive되게 꾸미기
    2.위 사진처럼 특이한 작동 시 에러 예외 처리
  • . 버튼을 활용하여, 소수를 입력받으세요.
  • . 버튼을 연속적으로 눌러도 .은 처음 단 한 번만 입력되어야 합니다.
  • 정수 부분 없이 . 버튼과 숫자를 눌러서 작동시키는 경우 소수가 나타나야 합니다. (.5 === 0.5)
  • Enter 버튼을 여러 번 클릭했을 때, 변수 previousNum 를 활용하여 - 이전 숫자를 계속 더할 수 있어야 합니다.
  • 연산자 버튼을 누르기 전 숫자 버튼을 누른 후에, 실수로 Enter를 여러 번 눌러도 정상 작동해야 합니다.
  • 연산자 버튼을 연속적으로 눌러도 계산 값에 영향이 없어야 합니다.
  • 숫자, 연산자, Enter의 순서로 눌렀을 때에도 작동해야 합니다.

의사코드


1. 숫자 버튼 : 사용자의 습관에 따라 만들기 위해 0에서 숫자를 누르면 0이 없어지고 계속 누르면 숫자가 이어붙어져야함, 그리고 연산자 버튼을 누른 후 2번째 숫자를 입력할 땐 1번째로 써진 숫자가 어떠한 변수로 남고 초기화돼서 입력돼야함
2. 연산자 버튼 : 위와 달리 연산자 버튼을 눌렀을 때 나타나진 않지만, 어느 하나의 변수로 남아 나중에 계산할 때 써어야하기 때문에 변수 따로 지정
3. 계산 버튼 : 1번째와 현재 숫자, 연산자를 변수로 잘 지정해야 계산이 됨, 계산 함수도 필수!
4. 초기화 버튼 : 모든 변수가 초깃값으로 회귀
5. Nightmare : 위 조건을 보며 dicimal, previousKey 등 추가

JS 코드 작성

// 계산 함수
function calculate(n11, operator, n22) {
  let result = 0;
  n1 = Number(n11);
  n2 = Number(n22);
  
  if (operator === "+") {
    result = n1 + n2;
  } else if (operator === "-") {
    result = n1 - n2;
  } else if (operator === "*") {
    result = n1 * n2;
  } else if (operator === "/") {
    result = n1 / n2;
  }
  return String(result);
}

// ! Advanced Challenge test와 Nightmare test(css파일의 62번 줄을 토대로 작성)
const display = document.querySelector(".calculator__display--for-advanced");
let operatorForAdvanced = "";
let firstNum = ""; // 연산자 전 처음 누른 숫자
let previousKey = ""; // 방금 누른 키, 이름("")을 설정하거나 값(display.textContent))을 설정해줘도 됨
let previousNum = ""; // 연산자 이후 누른 숫자

buttons.addEventListener("click", function (event) {
  // 버튼을 눌렀을 때 작동하는 함수입니다.
  const target = event.target; // 클릭된 HTML 엘리먼트의 정보가 저장되어 있습니다.
  const action = target.classList[0]; // 클릭된 HTML 엘리먼트에 클레스 정보를 가져옵니다.
  const buttonContent = target.textContent; // 클릭된 HTML 엘리먼트의 텍스트 정보를 가져옵니다.
  // ! 위 코드는 수정하지 마세요.
  // ! 여기서부터 Advanced Challenge & Nightmare 과제룰 풀어주세요.
  if (target.matches("button")) {
    if (action === "number") {
      if (display.textContent === "0" && operatorForAdvanced === "") {
        display.textContent = buttonContent;
        firstNum = display.textContent;
      } else if (display.textContent !== "0" && operatorForAdvanced === "") {
        display.textContent = display.textContent + buttonContent;
        firstNum = display.textContent;
      } else if (operatorForAdvanced !== "" && display.textContent !== "0") {
        if (previousKey === "operator") {
          // 왜 버튼은 안됨?
          display.textContent = buttonContent;
          previousNum = display.textContent;
        } else if (previousKey !== "operator") {
          display.textContent = display.textContent + buttonContent;
          previousNum = display.textContent;
        }
      }
      previousKey = "number";
    }
    if (action === "operator") {
      operatorForAdvanced = buttonContent;
      previousKey = "operator";
    }
    if (action === "decimal") {
      // "." 하나만 하기
      if (!display.textContent.includes(".") && previousKey !== "operator") {
        display.textContent = display.textContent + ".";
      } else if (previousKey === "operator") {
        display.textContent = "0.";
      }
      previousKey = "decimal";
    }
    if (action === "clear") {
      display.textContent = "0";
      firstNum = "";
      previousNum = "";
      operatorForAdvanced = "";
      previousKey = "clear";
    }
    if (action === "calculate") {
      if (firstNum) {
        if (previousKey === "calculate" && operatorForAdvanced !== "") {
          display.textContent = calculate(display.textContent, operatorForAdvanced, previousNum);
        } else if (operatorForAdvanced === "") {
          display.textContent = firstNum;
        } else {
          display.textContent = calculate(firstNum, operatorForAdvanced, display.textContent);
        }
      }
      previousKey = "calculate";
    }
  }
});
  • 너무 더러운 코드임,, 더 깔끔하게 만들려면 전에 어떻게 거를지 효율적으로 생각하기, 특히 숫자 버튼 코드
  • 효율적으로 조건을 써줘야 나중에 기능 추가로 인한 수정과 관리, 디버깅 등 더 쉽게 처리해줄 수 있음!
  • 아래 모범 코드를 보며 활용법을 생각하자

모범 코드

const calculator = document.querySelector('.calculator'); 
const buttons = calculator.querySelector('.calculator__buttons'); 

const firstOperend = document.querySelector('.calculator__operend--left'); 
const operator = document.querySelector('.calculator__operator');
const secondOperend = document.querySelector('.calculator__operend--right');
const calculatedResult = document.querySelector('.calculator__result'); 

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);
}

// ! Advanced Challenges, Nightmare
const display = document.querySelector('.calculator__display--for-advanced');
// 아래 조건에 truthy, falsy로 써주기 위해 undefined(falsy)로 설정
let firstNum, operatorForAdvanced, previousKey, previousNum;

buttons.addEventListener('click', function (event) {
  // 버튼을 눌렀을 때 작동하는 함수입니다.
  const target = event.target; // 클릭된 HTML 엘리먼트의 정보가 저장되어 있습니다.
  const action = target.classList[0]; // 클릭된 HTML 엘리먼트에 클레스 정보를 가져옵니다.
  const buttonContent = target.textContent; // 클릭된 HTML 엘리먼트의 텍스트 정보를 가져옵니다.
  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');
      }
    } // css 클래스 추가
    if (action === 'number') {
      if (display.textContent === '0' || previousKey === 'operator' || previousKey === 'calculate') {
        display.textContent = buttonContent;
      } else {
        display.textContent = display.textContent + buttonContent;
      }
      previousKey = 'number';
    }

    if (action === 'operator') { // 숫자 값은 truthy!
      target.classList.add('isPressed');
      if (firstNum && operatorForAdvanced && previousKey !== 'operator' && previousKey !== 'calculate') {
        display.textContent = calculate(firstNum, operatorForAdvanced, display.textContent);
      }
      firstNum = display.textContent;
      operatorForAdvanced = buttonContent;
      previousKey = 'operator';
    }

    if (action === 'decimal') {
      if (!display.textContent.includes('.') && previousKey !== 'operator') {
        display.textContent = display.textContent + '.';
      } else if (previousKey === 'operator') {
        display.textContent = '0.';
      }
      previousKey = 'decimal';
    }

    if (action === 'clear') {
      firstNum = undefined;
      operatorForAdvanced = undefined;
      previousNum = undefined;
      previousKey = 'clear';
      display.textContent = '0';
    }

    if (action === 'calculate') {
      if (firstNum) {
        if (previousKey === 'calculate') {
          display.textContent = calculate(display.textContent, operatorForAdvanced, previousNum);
        } else {
          previousNum = display.textContent;
          display.textContent = calculate(firstNum, operatorForAdvanced, display.textContent);
        }
      }
      previousKey = 'calculate';
    }
  }
});

알게된 점

애초에 코드를 짤 때 기획하는 것이 정말 중요하다고 느꼈다. 특히 조건문을 제시할 때 조건을 어떻게 작성하느냐에 따라 코드의 구성이 천차만별이란 걸 알게 됐다. 코드를 작성하면서 무조건 그러한 구조를 그리며 코드를 작성해야겠다.

profile
코뿔소처럼 저돌적으로

0개의 댓글