ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 자바스크립트 계산기 만들기 2: 계산기능 구현, 예외처리
    자바스크립트 2020. 4. 10. 08:26

    계산 기능 구현


    산술 연산자는 숫자 값을 피연산자로 받아 하나의 숫자 값을 반환합니다.
    표준 산술 연산자는 덧셈(+), 뺄셈(-), 곱셈(*), 나눗셈(/)입니다. - MDN

     

    자바스크립트에서 사칙연산과 관련된 산술 연산자는 +, -, *, /이다.

    10 + 2 // 12
    10 - 2 // 8
    10 * 2 // 20
    10 / 2 //5

    자바스크립트의 eval 함수를 사용하면 계산 기능을 쉽게 구현할 수 있다.

    eval()은 문자로 표현된 JavaScript 코드를 실행하는 함수이다.

     

    간단한 예로 a 변수에 2 + 3 * 5 연산식을 저장하고 eval 함수에 인자로 a를 넣고 실행하면 식이 계산된다.

    let a = '2 + 3 * 5'
    eval(a) // 17

     

    그럼 계속해서 클래스에 compute 메서드를 추가하고 eval() 함수를 사용해서 계산 기능 구현

    class Calculator {
        //...
        compute() {
            this.displayContent = eval(this.displayContent)        
        }
    }

     

    = 버튼 클릭 시 compute 메서드를 호출하도록 연결

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

     

     

    더하기와 빼기는 잘 되지만 곱하기와 나누기는 에러가 발생. 자바스크립트에서는 곱하기와 나누기가 ×, ÷가 아닌 *, / 를 사용하므로

    replace를 사용하여 × -> *로, ÷ -> / 로 변경해준 후 계산

    class Calculator {
        // ...
        compute() {
            this.displayContent = eval(this.displayContent
                .replace('\u00D7', '*')
                .replace('\u00F7', '/')
            )
        }
    }

     

    예외 처리


    큰 기능들은 완성했지만 아직 문제가 많다

     

    • 2++3처럼 연산자를 연속으로 입력할 수 있다.
    • ÷3 처럼 숫자보다 연산자가 먼저 입력이 가능하다.
    • 6X 처럼 식이 완전하지 않은 상태에서 = 버튼을 클릭하면 에러가 발생한다.
    • 2+3 = 5로 계산이 끝난 뒤 새로운 계산을 하기 위해 3을 입력하면 53으로 표시된다.

     

    첫 번째 문제부터 하나씩 고쳐 가보자

     

    2+ 를 입력하고 다시 연산자를 선택하면 입력되는 걸 막기 위해

    연산자 선택 여부를 관리하는 operatorCheck 속성을 추가

    class Calculator {
        constructor(displayElement) { 
            this.displayElement = displayElement
            this.operatorCheck = false // 연산자 선택 여부 저장
            this.clear()
        }    
    
        appendNumber(number) {
            this.displayContent += number
            this.operatorCheck = false // 숫자 입력 시 false
        }
    
        appendOperator(operator) {    
            if (this.operatorCheck) return // operatorCheck값이 true이면 함수 빠져나가기 
            this.displayContent += operator
            this.operatorCheck = true // 연산자 입력 시 true
        }    
    }

     

    appendOperator 메서드 호출 시 this.operatorChecktrue이면 (이미 연산자를 입력한 상태이면)  this.displayContent에 연산자를 추가하지 않고 빠져나감

     

    숫자를 입력한 뒤에는 다시 연산자를 입력할 수 있게 this.operatorCheckfalse로 변경

     


    그다음, ÷3 처럼 숫자 입력 전 연산자가 입력되는 걸 막기 위해 this.operatorCheck 초기값을 true로 변경

    class Calculator {
        constructor(displayElement) { 
            this.displayElement = displayElement
            this.operatorCheck = true // false -> true
            this.clear()
        }    
        //...
        appendOperator(operator) {    
            if (this.operatorCheck) return
            this.displayContent += operator
            this.operatorCheck = true        
        }    
    }
    // ...
    buttons.forEach(button => {
        button.addEventListener('click', () => {
            switch (button.dataset.type) {
                case 'operator':                
                    calculator.appendOperator(button.innerText)
                    calculator.updateDisplay()                               
                    break            
            }
        })      
    })

     

    초기값이 true이기에 숫자 입력 전에 연산자를 클릭하면 연산자가 this.displayContent에 추가되지 않고 빠져나간다.

    다만, 빠져나가는 거와는 상관없이 this.updateDisplay()가 실행되기 때문에 appendOperatortrue를 리턴할 때만 업데이트되도록 수정한다.

    class Calculator {
        constructor(displayElement) { 
            this.displayElement = displayElement
            this.operatorCheck = true
            this.clear()
        }    
        //...
        appendOperator(operator) {    
            if (this.operatorCheck) return false
            this.displayContent += operator
            return this.operatorCheck = true       
        }    
    }
    // ...
    buttons.forEach(button => {
        button.addEventListener('click', () => {
            switch (button.dataset.type) {
                case 'operator':                
                   if (calculator.appendOperator(button.innerText)) {
                        calculator.updateDisplay()
                    }  
                    break          
            }
        })      
    })

     

    이렇게 하면 연산자가 먼저 입력되지는 않지만 숫자를 입력 -> AC 버튼 클릭 -> 연산자를 선택해보면 여전히 입력이 가능하다

    clear 메서드에 this.operatorCheck = true를 추가해 연산자가 입력되지 않도록 막는다.

    class Calculator {
        //...
        clear() {
            this.displayContent = ''
            this.displayElement.value = 0
            this.operatorCheck = true
        }
    }

     

     


    6X 를 입력 후 = 버튼을 클릭하면 잘못된 식이기 때문에 에러가 발생한다.

    연산자가 마지막으로 입력된 상태일 경우 = 버튼을 클릭해도 eval() 함수가 동작되지 않도록 코드를 수정한다.

    class Calculator {
       //...
        compute() {
            if (this.operatorCheck) return // 추가
            this.displayContent = eval(this.displayContent
                .replace('\u00D7', '*')
                .replace('\u00F7', '/')
            )
        }
    }

    2+3 = 5로 계산을 끝낸 뒤 숫자를 입력하면 전에 계산되었던 결과에 입력한 숫자가 이어져 나타나고 있다.

     

    = 버튼을 클릭 후 숫자를 클릭한다면 AC기능과 비슷하게 새로운 식 입력을 시작하는거니

    appendNumber 메서드에서 this.displayContent += number로 숫자가 추가되던걸

    = 버튼을 클릭 후 처음으로 숫자를 클릭할 때만 this.displayContent = number로 바로 초기화되게 한다.

    = 버튼을 클릭했는지 알아내기 위해 operatorCheck처럼 equalsCheck 속성을 하나 추가해 = 버튼 클릭 여부를 관리한다

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

     

     

    이제 = 버튼 클릭 후 숫자를 입력하면 이전 결과에 숫자가 이어져 나오지 않고 잘 동작되지만

    = 버튼 클릭 -> 연산자 클릭 -> 숫자를 클릭하면 이상하게 입력되고 있다.

     

    2 + 3 계산 후 5 + 2를 입력하고 싶었는데 + 를 클릭 후 2를 선택하니 입력 중이던 식이 사라지고 2만 나타나버렸다

    class Calculator {
        //...
        appendOperator(operator) {    
            if (this.operatorCheck) return false
            if (this.equalsCheck) this.equalsCheck = false // 추가
            this.displayContent += operator
            return this.operatorCheck = true         
        }
    }

    appendOperator 메서드에도 equalsChecktrue일 경우 false로 바꿔주는 코드를 추가한다

     

    잘 된다


    아직 많이 부족하고 완벽한 계산기는 아니지만 이 정도면 만족한다.

     

    댓글

Designed by Tistory.