본문 바로가기
코딩/뭔가 만들어 보기

자바스크립트 계산기 만들어서 티스토리 블로그에 올리기

by Say_Young 2021. 8. 16.

[자바스크립트 계산기 만들어서 티스토리 블로그에 올리기]

 

See the Pen SimpleCalculator by YYYSYYY (@SayYoung) on CodePen.

 

 

아래 사이트 참고하여, 티스토리 블로그에 자바스크립트를 이용하여 계산기 만드는 과정을 배웠음

(https://kanhi.tistory.com/2)

아래 내용은 위 블로그의 글과 거의 흡사하고, 중간중간 의문가는 사항이나 이해하는 과정에서의 코멘트를 파란 글씨로 추가했음. 

 

1. 태그 배우기

- <button/> 태그를 통해 유저가 숫자나 연산자를 클릭할 수 있게 한다

- <button/> 을 격자로 표현하기 위해 <div/>를 사용한다.

- 사용자로부터 값을 입력받을 <input/>

 

2. 뼈대 만들기

 

아래와 같이 폴더와 html파일을 만든다. 

 

 

 

 

html 코드 작성

<!DOCTYPE html>

<html lang="en">

<head>

    <meta charset="UTF-8">

    <!--위 태그는 html파일의 인코딩을 알려주는 태그다.

    브라우저에게 text를 어떻게 그려달라는 것인지 말해주는 것으로,

    위 태그가 없으면 특수문자 등이 제대로 표시되지 않을 수 있다-->

    <meta name="viewport" content="width=device-width, initial-scale=1.0">

    <!--viewport란 화면상의 표시 영역을 말함. contnet=device-width로 하면

    장치 크기에 맞게 표시되므로 추천.

    initial-scale은 뷰포트의 초기 배율을 뜻하며 보이는 영역에서 웹페이지에 맞추기 위해 계산됨-->

    <title>Calculator</title>

    <link rel="stylesheet" href=“style.css">

    <!--링크 태그에 달리는 링크가 현재 페이지와 어떤 관계를 갖는지 설명하는 attribute다.

    현재 페이지의 스타일을 꾸미는 데 사용되는 스타일시트인 "style.css"를 불러오라는 것이다.

    현재 html페이지와의 관계(rel)은 stylesheet, 그 스타일시트를 어디서 가져오냐면

    "style.css"에서 가져오라는 것이다.-->

</head>

<body>

    <main>

        <input type="text" disabled>

        <!--"text"타입의 요소는 사용자가 클릭할 수 없고 사용할 수 없음.-->

        <div class="button-wrap">

        <!--"button-wrap"이라는 class를 생성하고, 버튼을 만들어 준다.-->

            <button>AC</button>

            <button>&divide;</button>

            <!--&divide;는 나눗셈 표시를 위한 html 토큰이다.-->

            <button>7</button>

            <button>8</button>

            <button>9</button>

            <button>&times;</button>

            <!--&times;는 곱셈 표시를 위한 html 토큰이다.-->

            <button>4</button>

            <button>5</button>

            <button>6</button>

            <button>-</button>

            <button>1</button>

            <button>2</button>

            <button>3</button>

            <button>+</button>

            <button>0</button>

            <button>.</button>

            <button>=</button>

        </div>

    </main>

</body>

</html>

 

* 여기까지 결과 화면 

 

이걸 계산기 모양대로 바꿔줘야 한다. css파일을 이용한다.

 

3. css파일 만들기 

 

 

*css 문법 이해

 

css의 문법은 선택자와 선언부로 구성됨. 

선택자는 css 적용을 위한 html요소를 가리킨다. 선언부는 하나 이상의 세미콜론으로 구분하여 포함 가능하며

 중괄호로 전체를 둘러싼다.

 

(출처: http://tcpschool.com/css/css_intro_syntax)

 

*css 선택자는 다음과 같다

 

- Html 요소 선택자

h2 { color: tealtext-decoration: underline; }

 

- Id 요소 선택자

#heading { color: tealtext-decoration: line-through; }

 

Class 선택자

.headings { color: limetext-decoration: overline; }

 

html요소는 특수문자 없이 선택하면 되고, id요소는 #기호, Class요소는 .기호를 앞에 붙여서 선택하는 것을 있다.

 

Group 선택자(위의 여러 선택자를 같이 사용하고자 할 때)

 

h1 { color: navy; }

h1h2 { text-align: center; }

h1h2p { background-color: lightgray; }

 

*css 코드

 

/* style.css */

/* main이라는 엘리먼트의 너비를 150으로 고정함 */

/*main 이라는 html요소를 선택자로 하고 넓이를 150픽셀로 설정*/

main {

    width: 150px;

}

 

/*button-wrap이라는 class 요소를 선택자로 하고, grid 디스플레이 적용, 

repeat(반복횟수, 반복값)

*/

.button-wrap {

    display: grid;

    /* 한 줄에 4개씩, 모두 동일한 비율 적용(1:1:1:1) */

    grid-template-columns: repeat(4, 1fr);

}

 

* 여기까지 결과화면 

 

 

 

 

 

4. 별로 예쁘지 않으니까 버튼 크기 등을 조절해 준다

 

아래처럼 바꿔주려 한다.  

 

 

css에서 조정해 줘야 하는데, a버튼과 0버튼은 다른 버튼과 크기가 다르다.

Html 코드에서 class 를 추가하여 css에서 다룰 수 있게 해 준다.

 

 

- html 코드 수정

    <main>

        <!--"text"타입의 요소는 사용자가 클릭할 수 없고 사용할 수 없음.-->

        <input type="text" disabled>

        <!--"button-wrap"이라는 class를 생성하고, 버튼을 만들어 준다.-->

        <div class="button-wrap">

            <!-- ac 클래스 추가 -->

            <button class="ac">AC</button>

            <!--&divide;는 나눗셈 표시를 위한 html 토큰이다.-->

            <button>&divide;</button>

            <button>7</button>

            <button>8</button>

            <button>9</button>

            <!--&times;는 곱셈 표시를 위한 html 토큰이다.-->

            <button>&times;</button>

            <button>4</button>

            <button>5</button>

            <button>6</button>

            <button>-</button>

            <button>1</button>

            <button>2</button>

            <button>3</button>

            <button>+</button>

            <!-- zero 클래스 추가 -->

            <button class="zero">0</button>

            <button>.</button>

            <button>=</button>

        </div>

    </main>

 

 

-css 코드 추가

 

/*ac버튼 크기 조정*/

.ac {

  /*4등분하여 나온 5개의 선 중에서 첫번째 선부터 4번째 선까지 지정*/

  grid-column: 1/4;

}

 

/*0버튼 크기 조정*/

.zero {

  /*4등분하여 나온 5개의 선 중에서 첫번째 선부터 3번째 선까지 지정*/

  grid-column: 1/3;

}

 

 

 

*여기까지 결과화면

 

 

 

5. input 태그 스타일 설정(꾸미기)

 

여긴 색칠하고 그런거니까.. 복붙 하고 넘어가고 나중에 공부하기로 하자. 우선 기능을 만들어 보자

 

- css파일에 아래와 같이 추가해 준다.

 

* {

    box-sizing: border-box;

    color: white;   

}

input, button {

    height: 35px;

    outline: none;

}

input {

    width: 100%;

    text-align: right;

    border: none;    

    background: #5B5B5D;

    padding-right: 1rem;

    font-size: 2rem;

}

 

 

6. 버튼 태그 스타일 설정(꾸미기)

 

여기도 마찬가지로 복붙하고 넘어간다.

 

- css 코드 수정

button {

    background: #828284;

    border: 1px solid #454448;

    font-size: 1rem;

}

/* nth-child(4n+2): 4번째 요소마다 스타일을 적용하는데 처음에만 두번째에 적용 */

button:nth-child(4n+2), button:last-child  {

    background-color: orange;

}

button:hover {

    opacity: .5;

}

 

/*ac버튼 크기 조정*/

.ac {

  /*4등분하여 나온 5개의 선 중에서 첫번째 선부터 4번째 선까지 지정*/

  grid-column: 1/4;

  background: #6A6A6C;

}

 

/*0버튼 크기 조정*/

.zero {

  /*4등분하여 나온 5개의 선 중에서 첫번째 선부터 3번째 선까지 지정*/

  grid-column: 1/3;

}

 

 

*여기까지 결과화면 

 

 

7. 버튼 클릭 시 input에 추가

 

버튼을 클릭하면 값이 입력되도록 하는 작업이다. data-type에 따라 동작을 다르게 처리하기 위해, 숫자 버튼을 제외하고 data-type 속성을 추가해 준다

 

- ac버튼 : data-type=“ac”

- 연산자 버튼 : data-type=“operator”

- = 버튼 : data-tyle =“equals”

 

- html 코드 수정

 

    <main>

        <!--"text"타입의 요소는 사용자가 클릭할 수 없고 사용할 수 없음.-->

        <input type="text" disabled>

        <!--"button-wrap"이라는 class를 생성하고, 버튼을 만들어 준다.-->

        <div class="button-wrap">

            <!-- ac 클래스 추가 -->

            <button data-type="ac" class="ac">AC</button>

            <!--&divide;는 나눗셈 표시를 위한 html 토큰이다.-->

            <button data-type="operator">&divide;</button>

            <button>7</button>

            <button>8</button>

            <button>9</button>

            <!--&times;는 곱셈 표시를 위한 html 토큰이다.-->

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

            <!-- zero 클래스 추가 -->

            <button class="zero">0</button>

            <button>.</button>

            <button data-type="equals" class="equals">=</button>

        </div>

    </main>

 

*자바스크립트 파일을 만든다(파일명:script.js) 

 

8. 버튼과 input 태그를 가져와서 변수에 담는다

 

- javascript 코드

const buttons = document.querySelectorAll('button')

//자바스크립트 코드에 ‘buttons’ 라는 변수를 선언한다. css 문서 내의 ‘button’이라는 선택자에 해당하는 모든 요소를 리스트 타입으로 반환한다. 계산기에서 버튼들을 의미한다.

const displayElement = document.querySelector('input')

//자바스크립트 코드에 ‘displayElemnet’ 라는 변수를 선언한다. css 문서 내의 ‘input’이라는 선택자에 해당하는 모든 요소를 리스트 타입으로 반환한다. 계산기에서 입력된 내용을 보여주는 부분이다.

 

querySelector()

document.querySelector() 입력한 선택자와 일치하는 문서 내의 번째 element 반환한다. 일치하는 요소가 없다면 null 반환한다. 괄호 안에 들어가는 매개변수는 유효한 CSS 선택자여야한다

 

querySelectorAll()

querySelector() 개의 요소를 반환했다면, querySelectorAll() 주어진 CSS 선택자와 일치하는 모든 요소를 반환한다. 이때, 반환 타입은 리스트 타입이다. 따라서 인덱스를 통해 조작할 있다.

 

 

9. html 파일에 script.js 연결

 

<body>

    <main>

        <!-- ... -->            

    </main>

    <script src="script.js"></script>

</body>

 

10. Calculator 클래스 만들고 인스턴스 생성

 

슨말인지 모르겠다. 클래스는 뭐고 인스턴스는 뭘까.

예를 들면 이런 거라고 한다.

 

붕어빵틀 = class

붕어빵 = object

각각의 붕어빵 = instance

붕어빵을 굽다 = 인스턴스(instance)화 하다

 

생성자(constructor) = 

클래스를 생성할 때 생성자는 반드시 존재해야 한다

생성자를 선언할 때 클래스의 이름과 생성자의 이름은 반드시 같아야 한다.

constructor 매서드(작업)는 class 내에서 객체를 생성하고 초기화하기 위한 특별한 메서드다.

 

내가 하는 작업에 적용해 보자면, “계산기붕어빵틀, class”이다. 무언가를 만들기 위한 기본 뼈대다. 도구를 통해서 입력값을 받아서결과값 내놓을 것이다. 결과값붕어빵,instance”이라고 이해하면 같다. instance 구체적인 상태(variable, 변수) 행위(method, 기능) 집합이다.

 

생성자의 개념은 닿지 않는다. 비유하자면 생성자(constructor) 업무를 하기 전에 하는 책상정리와 비슷하다고 한다(초기화).

(참조: https://whatisthenext.tistory.com/1)

 

class Calculator {

//class 선언한다

    constructor(displayElement) { 

//생성자 함수를 통해 displatElement 초기상태를 지정하기 위한 책상정리를 한다.

        this.displayElement = displayElement

//this 인스턴스 자신을 가리키는 참조변수다.

//Calculator클래스의 안에 있는 인스턴스 변수 displayElement displayElement 담는다

        this.displayContent = ''

//Calculator클래스의 안에 있는 인스턴스 변수 displayContent 빈 문자열을 담는다

    }    

}

 

const buttons = document.querySelectorAll('button')

const displayElement = document.querySelector('input')

 

const calculator = new Calculator(displayElement)

//new 함수를 통해 Calculator라는 객체를 만든다. 객체에는 위에서 정의한 것과 같이 displayElement displayContent 세팅되어 있다.

 

 

11. addEventListener로 모든 버튼에 클릭 이벤트를 연결하고 switch문으로 data-type에 따라 버튼 구분하기

 

event란 '사용자가 어떤 결과를 유발시킬만한 행동을 하는 것'이다. 사용자가 클릭을 한다거나 페이지를 넘긴다거나 하는 것을 말한다.

 

자바스크립트에서는 특정 이벤트가 발생했을 시 특정 함수를 실행할 수 있게 해주는 addEventListener라는 기능이 존재한다.

 

 addEventListener 등으로 등록할 있는 이벤트 자주 쓰이는 이벤트 목록

(출처: https://m.blog.naver.com/PostView.naver?isHttpsRedirect=true&blogId=qbxlvnf11&logNo=220877806711)

이벤트 설명
change 변동이 있을 발생
click 클릭시 발생
focus 포커스를 얻었을 발생
keydown 키를 눌렀을 발생
keyup 키에서 손을 땟을 발생
load 로드가 완료 되었을 발생
mousedown 마우스를 클릭 했을 발생
mouseout 마우스가 특정 객체 밖으로 나갔을 발생
mouseover 마우스가 특정 객체 위로 올려졌을 발생
mousemove 마우스가 움직였을 발생
mouseup 마우스에서 손을 땟을 발생
select option 태그 등에서 선택을 햇을 발생

 

 

 

// ...

const buttons = document.querySelectorAll('button')

const displayElement = document.querySelector('input')

 

const calculator = new Calculator(displayElement)

 

//arrow함수 forEach문은 다음과 같다.

//리스트.forEach(원소=>함수(원소)); 

//리스트 내의 원소를 함소 안에 차례로 넣는다.

buttons.forEach(button => {

<<!--대상객체.addEventListener('이벤트명', fuction 함수명(event){}) = ‘이벤트만들기’)

화살표 함수는 function 키워드 대신 화살표를 사용하여 간략하게 함수를 선언하는 것이다

매개변수가 없는 경우 

()=>{…}

처럼 사용할 있다.-->

    button.addEventListener('click', () => {

<!-- data-type html코드에서 요소별로 부여했다. button.dataset.type 부분은 button 데이터타입을 가져오는 것이고,

케이스별로 분류하여 'operator', 'ac', 'equals' 비교하여 일치여부 판단하고 콘솔 로그에 표시한다.-->

        switch (button.dataset.type) {

            case 'operator':

                console.log('operator')

                break

            case 'ac':

                console.log('ac')

                break

            case 'equals':

                console.log('equals')

                break

            default:

                console.log('number')

                break

        }

    })      

})

 

12. 숫자 버튼을 클릭할 때마다 displayContent 속성에 숫자가 추가되고 input에도 표시되도록 appendNumber, updateDisplay 메서드 추가 switch문의 default에서 추가한 메서드 호출

class Calculator {

    constructor(displayElement) { 

        this.displayElement = displayElement

//this.displaycontent='' 라고 표시했다. 따옴표 표시했으므로 자료형은 문자열이다.

        this.displayContent = ''

    }    

 

//appendNumber 메서드(작업) 추가

    appendNumber(number) {

//+= 복합대입연산자인데, this.displayContent = this.displayContent + number 같은 의미를 가진다. 문자열(String) +기호를 경우 덧셈을 하라는 것이 아니라 문자열을 잇는다는 것이다. ex) 10 + 1 = 101

        this.displayContent += number

    }

 

//updateDisplay 메서드(작업)추가.

//this.displayElemnet (value) this.displayContent 담는다.

    updateDisplay() {

        this.displayElement.value = this.displayContent

    }

}

 

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':

                console.log('operator')

                break

            case 'ac':

                console.log('ac')

                break

            case 'equals':

                console.log('equals')

                break

            default:

                calculator.appendNumber(button.innerText)

                calculator.updateDisplay()

                break

        }

    })      

})

 

13. 마찬가지로 클래스에 appendOperator 메서드 추가 후 연산자 버튼 클릭 시 호출되도록 연결

 

 

    class Calculator {

    constructor(displayElement) { 

        this.displayElement = displayElement

        this.displayContent = ''

    }    

 

    appendNumber(number) {

        this.displayContent += number

    }

 

//this.displayContent = this.displayContent + operator 의미다.

    appendOperator(operator) {            

        this.displayContent += operator

    }

 

    updateDisplay() {

        this.displayElement.value = this.displayContent

    }

}

 

const buttons = document.querySelectorAll('button')

const displayElement = document.querySelector('input')

 

const calculator = new Calculator(displayElement)

 

//클릭한 버튼이 연산자이면, calculator 클래스의 appendOperator 메서드를 추가한다.

//element.innerText; 자바스크립트에 내장된 기능이다. HTML element 안의 텍스트를 가져온다.

buttons.forEach(button => {

    button.addEventListener('click', () => {

        switch (button.dataset.type) {

            case 'operator':

                calculator.appendOperator(button.innerText)

                calculator.updateDisplay()

                break

            //...

        }

    })      

})

 

14. AC 기능 구현

 

* ac버튼을 누르면 모든 입력이 초기화되도록 클래스에 clear 메서드 추가 후 ac버튼과 연결

 

class Calculator {

    // ...

    clear() {

        this.displayContent = ''

        this.displayElement.value = 0

    }

}

 

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 'ac':

                calculator.clear()                

                break

            //...

        }

    })      

})

 

* constructor에서도 clear 메서드를 호출하도록 수정

 

class Calculator {

    constructor(displayElement) {

        this.displayElement = displayElement

        this.displayContent = ''

        this.clear()

    } 

 

* 여기까지 결과화면

 

 

15. 계산 기능 구현

 

*eval() 함수.

 

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

 

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

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

 

 

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

 

let a = '2 + 3 * 5'

eval(a) // 17

 

class Calculator {

    //...

    compute() {

        this.displayContent = eval(this.displayContent)        

    }

}

 

* 계속해서 클래스에 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

//"\u00D7" ×, "\u00F7" ÷ 의미한다.

            .replace('\u00D7', '*')

            .replace('\u00F7', '/')

        )

    }

}

 

* 여기까지 결과화면. 기본적인 기능을 한다.

 

댓글