부트캠프/따로 공부

HTML CSS Javascript 계산기 구현하기 (js 로직 이해 과정 위주로)

하이고니 2022. 12. 24. 01:29
 

자바스크립트 계산기 만들기 2: 계산기능 구현, 예외처리

계산 기능 구현 산술 연산자는 숫자 값을 피연산자로 받아 하나의 숫자 값을 반환합니다. 표준 산술 연산자는 덧셈(+), 뺄셈(-), 곱셈(*), 나눗셈(/)입니다. - MDN 자바스크립트에서 사칙연산과 관련

kanhi.tistory.com

아래 나오는 코드는 모두 위 블로그 복붙입니다.

이 분의 설명 굉장히 굉장합니다.

위 글은 자바스크립트를 처음 시작하고 계산기 만드는 것에 좌절하고 있던 제게, 한 줄기 빛이 되어주었습니다.

글 쓰신 분께 큰 감사의 말씀을 드립니다.

 

HTML

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Cal</title>
    <link rel="stylesheet" href="style.css">
</head>

<body>
    <main>
        <input type="text" disabled>
        <div class="button-wrap">
            <button data-type="ac" class="ac">AC</button>
            <button data-type="operator">&divide;</button>
            <button>7</button>
            <button>8</button>
            <button>9</button>
            <button data-type="operator">&times;</button>
            <button>4</button>
            <button>5</button>
            <button>6</button>
            <button data-type="operator">-</button>
            <button>1</button>
            <button>2</button>
            <button>3</button>
            <button data-type="operator">+</button>
            <button class="zero">0</button>
            <button>.</button>
            <button data-type="equals" class="equals">=</button>
        </div>
    </main>
    <script src="script.js"></script>
</body>

</html>

CSS

/* style.css */
main {
    width: 300px;
}

.button-wrap {
    display: grid;
    /* 한 줄에 4개씩, 모두 동일한 비율 적용(1:1:1:1) */
    grid-template-columns: repeat(4, 1fr);
}

.ac {
    /* 첫 번째 선부터 4번째 선까지 지정 */
    grid-column: 1/4;
}

.zero {
    /* 첫 번째 선부터 3번째 선까지 지정 */
    grid-column: 1/3;
}

* {
    box-sizing: border-box;
    color: white;
}

input,
button {
    height: 70px;
    outline: none;
}

input {
    width: 100%;
    text-align: right;
    border: none;
    background: #5B5B5D;
    padding-right: 1rem;
    font-size: 3rem;
}

button {
    background: #828284;
    border: 1px solid #454448;
    font-size: 2rem;
}

/* nth-child(4n+2): 4번째 요소마다 스타일을 적용하는데 처음에만 두번째에 적용 */
button:nth-child(4n+2),
button:last-child {
    background-color: orange;
}

button:hover {
    opacity: .5;
}

.ac {
    grid-column: 1/4;
    background: #6A6A6C;
}

.zero {
    grid-column: 1/3;
}​

Javascript

class Calculator {
    constructor(displayElement) {
        this.displayElement = displayElement
        this.operatorCheck = true
        this.equalsCheck = false
        this.clear()
    }
    appendNumber(number) {
        if (this.equalsCheck) {
            this.displayContent = number // 마지막에 누른 것이 '=' 라면 새로운 식 입력
            this.equalsCheck = false; // = 버튼 클릭 여부 관리
        } else {
            this.displayContent += number // 마지막에 누른 것이 '=' 가 아니라면 기존 식에 추가
        }
        this.operatorCheck = false // 숫자 입력시 false
    }
    appendOperator(operator) {
        if (this.operatorCheck) return false
        if (this.equalsCheck) this.equalsCheck = false
        this.displayContent += operator
        return this.operatorCheck = true
    }
    updateDisplay() {
        this.displayElement.value = this.displayContent
    }
    clear() {
        this.displayContent = ''
        this.displayElement.value = 0
        this.operatorCheck = true
    }
    compute() {
        this.equalsCheck = true
        if (this.operatorCheck) return

        this.displayContent = eval(this.displayContent
            .replace(/\u00D7/gi, '*')
            .replace(/\u00F7/gi, '/')
        )
    }
}


const buttons = document.querySelectorAll('button')
const displayElement = document.querySelector('input')

const calculator = new Calculator(displayElement)

buttons.forEach(button => {
    button.addEventListener('click', () => {
        switch (button.dataset.type) {
            case 'operator':
                if (calculator.appendOperator(button.innerText)) {
                    calculator.updateDisplay()
                }
                break
            case 'ac':
                calculator.clear()
                break
            case 'equals':
                calculator.compute()
                calculator.updateDisplay()
                break
            default:
                calculator.appendNumber(button.innerText)
                calculator.updateDisplay()
                break
        }
    })
})

 

다른 건 차치하고 javascript 이해하는 것이 너무 어려워서

세 시간 동안 계속 머리 터지도록 생각했고, 그것을 토대로 대충 이해한 내용을 적어보겠다.

 

 

1. 숫자 3을 입력한다

 

button.innerText 가 number 기 때문에

appendNumber 로 들어간다

 

equalsCheck 를 하는데 기본값이 false 기 때문에

displayContent 에 += 3

 

0 이었던 displayElement.value 에 3 이 다시 할당됨

 

그리고 다시 맨 밑에 calculator.updateDisplay() 가 실행된다 

 

 

현재 계산기 안의 값은 3

 

 

근데 어떻게 HTML 의 input text 창에

3이 넘어가는 건지는 아직 모르겠음 (js 와 HTML 의 연결고리가 뭘까)

 

-> 제일 처음에 displayElement 에 input 셀렉터에서 가져온 값을 할당하기 때문이 아닐까 싶긴 함.

정확한 원리는 모르겠음.

 

// const displayElement = document.querySelector('input') 참고

 

 

 

그리고 operatorCheck 를 false 로 바꾸면서 한 턴 마무리

 

 

 

 

2. + 를 입력한다

 

button.innerText 가 operator 기 때문에

appendOperator 로 들어간다

 

operatorCheck 를 하는데 방금 3을 입력하면서 값이 false 로 바뀌었기 때문에

if 문을 건너뛰고 true 값을 return 한다

 

그리고 operatorCheck 는 다시 true 로 바뀐다

 

맨 밑에 case ‘operator’ 에서

if 문 안의 것을 수행한다. // calculator.updateDisplay()

 

현재 계산기 안의 값은 3+

현재 operatorCheck 는 true

 

 

3. 이번엔 - 를 입력해본다

 

button.innerText 가 operator 기 때문에

appendOperator 로 들어간다

 

operatorCheck 가 true 이므로 false 값을 리턴한다

 

맨 밑에 case ‘operator’ 에서

if 문을 건너뛰고 break 걸려 빠져나간다 ( - 라는 기호가 계산기에 입력되지 않음)

 

 

4. 숫자 2를 입력한다

 

button.innerText 가 number 기 때문에

appendNumber 로 들어간다

 

equalsCheck 를 하는데 기본값이 false 기 때문에

displayContent 에 += 2

 

맨 밑에 calculator.updateDisplay() 가 실행된다

현재 계산기 안의 값은 3+2

 

그리고 operatorCheck 를 false 로 바꾸면서 한 턴 마무리

 

 

5. = 를 입력한다

 

button.innerText 가 equals 이기 때문에

calculator.compute() 실행

 

compute() 가 실행되면서

equalsCheck 가 true 로 바뀜 

// 이게 참조한 블로그에 빠져 있었다. 계산이 끝난 뒤 결과값이 계산기에 출력되고 있을 때,

새로운 숫자가 입력되면 초기화가 돼야 정상인데 계속 결과값에 숫자가 추가돼가지고 헤맸음..

 

operatorCheck 는 false 이므로 return 되지 않고 밑에 있는 명령 실행 (곱셈 기호와 나눗셈 기호를 * / 처럼 생각하고 계산하라)

그리고 맨 밑에 updateDisplay 를 실행하고 종료

 

현재 계산기 안의 값은 5

 

현재 equalsCheck true

현재 operatorCheck false

 

 

 

6. 다시 숫자 7을 입력한다

 

button.innerText 가 operator 기 때문에

appendOperator 로 들어간다

 

equalsCheck 를 하는데 방금 true 로 바뀌었기 때문에

displayContent 는 += 7 이 아니라 새로 7이 할당됨

 

그리고 equalsCheck 는 다시 false 로 변경되고

operatorCheck 를 false 로 바꾸면서 턴 종료

 

현재 계산기 안의 값은 7

 

현재 operatorCheck false

현재 equalsCheck false

 

이렇게 계속 진행된다….

 

 

6-1. 계산이 끝난 뒤 연산자를 입력할 경우

 

현재 계산기 안의 값은 5

현재 equalsCheck true

현재 operatorCheck false

 

 

+ 를 입력한다

button.innerText 가 operator 기 때문에

appendOperator 로 들어간다

 

operatorCheck 가 false 이므로 if 문을 건너뛰고

다음 if 문으로 넘어간다

equalsCheck 가 true 이므로 equalsCheck 를 false 로 바꿔준다

 

*이렇게 하지 않으면 계산이 끝난 뒤에

+ 입력

2 입력하면

 

5, 5+, 7 이렇게 연산되지 않고

5, 5+, 2 이렇게 리셋된다

 

 

마치며...

뭐 이렇게까지 재밌나 싶을 정도로 시간 가는 줄 모르게 재밌다.

더 열심히 해서 이정도는 진짜 그냥 소설책 읽듯이 이해하고 싶다.

마지막으로 다시 한 번 저 블로그의 주인 kanhi 씨께 감사의 말을 전한다.

 

제일 처음에 displayElement 에 input 셀렉터에서 가져온 값을 할당하기 때문이 아닐까 싶긴 함.

정확한 원리는 모르겠음.

 

이거 알고싶다...

 

 

자바스크립트 계산기 만들기 2: 계산기능 구현, 예외처리

계산 기능 구현 산술 연산자는 숫자 값을 피연산자로 받아 하나의 숫자 값을 반환합니다. 표준 산술 연산자는 덧셈(+), 뺄셈(-), 곱셈(*), 나눗셈(/)입니다. - MDN 자바스크립트에서 사칙연산과 관련

kanhi.tistory.com

 

'부트캠프 > 따로 공부' 카테고리의 다른 글

font awesome 사용 방법  (0) 2023.01.20
Javascript reduce() 메서드  (0) 2023.01.03
오늘의 목표  (0) 2022.12.22
생활코딩 WEB1, NAV BAR  (0) 2022.12.17
HTML 1일차 <a><a/>, <img> 태그와 target  (0) 2022.12.16