1.  이벤트 설정하기

🐝  이벤트 : 사이트에서 방문자가 취하는 모든 행위
         ▶️  모든 문서 객체는 생성되거나 클릭되거나 마우스를 위에 올리거 나 할 때 이벤트가 발생
🐝  이벤트 핸들러 (= 이벤트 리스너) : 이벤트가 발생했을 때 실행되는 코드 (함수)

 

(1) 이벤트 핸들러 등록 종류


  1) 이벤트 핸들러 어트리뷰트 방식

 

    👩🏻‍💻 이벤트 핸들러 어트리뷰트는 onclick과 같이 on 접두사와 이벤트의 종류를 나타내는 이벤트 타입으로 이루어져 있음
    👩🏻‍💻  주의할 점은 이벤트 핸들러 어트리뷰트 값으로 함수 참조가 아닌 함수 호출문 등의 문을 할당
           ➡️  이때 이벤트 핸들러 어트리뷰트 값은 사실 암묵적으로 생성될 이벤트 핸들러의 함수 몸체를 의미
           ➡️  하지만 HTML과 자바 스크립트는 관심사가 다르므로 혼재하는 것보다 분리하는 것이 좋음

<body>
    <button onclick="sayHi('Lee')">Click me!</button>
    <script>
        function sayHi(name) {
            console.log(`Hi! ${name}`); // Hi! Lee
        }
    </script>
</body>

 



  (2) 이벤트 핸들러 프로퍼티 방식

 

    👩🏻‍💻  window 객체와 Document, HTMLElement 타입의 DOM 노드 객체는 이벤트에 대응하는

          이벤트 핸들러 '프로퍼티'를 가지고 있음
    👩🏻‍💻  이벤트 핸들러 프로퍼티의 키는 on 접두사와 이벤트의 종류를 나타내는 이벤트 타입으로 이루어져 있음
    👩🏻‍💻  이벤트 핸들러 프로퍼티 방식은 이벤트 핸들러 어트리뷰트 방식의 HTML과 자바 스크립트가 뒤섞이는 문제를 해결할 수 있음
           ▶️ 하지만 이벤트 핸들러 프로퍼티에 하나의 이벤트 핸들러만 바인딩할 수 있다는 단점이 있음

<body>
    <button>Click me!</button>
    <script>
        const btn = document.querySelector('button');
        console.log(typeof btn); // object

        // 이벤트 핸들러 프로퍼티에 이벤트 핸들러 바인딩.
        // 첫 번째로 바인딩 된 이벤트 핸들러는 두 번째 바인딩된 이벤트 핸들러에 의해 재할당되어 실행되지 않음.
        btn.onclick = function () {
            console.log('button click 1');
        };

        btn.onclick = function () {
            console.log('button click 2');
        };
    </script>
</body>

 


 

  (3)  addEventListener 메서드 방식

 

문서 객체.addEventListener(이벤트 이름, 콜백 함수)
      ⚡️  첫 번째 매개변수에는 이벤트의 종류를 나타내는 문자열인 이벤트 타입을 전달
             ( 이 때 이벤트 핸들러 프로퍼티 방식과는 달리 on 접두사를 붙이지 않음 )
      ⚡️  두 번째 매개변수에는 이벤트 핸들러를 전달


     👩🏻‍💻  DOM Level 2에서 도입된 Event.prototype.addEventListener 메서드를 사용하여 이벤트 핸들러를 등록할 수 있음
     👩🏻‍💻  '이벤트 핸들러 어트리뷰트 방식'과 '이벤트 핸들러 프로퍼티 방식'은 DOM Level 0 부터 제공되던 방식

<body>
    <button>Click me!</button>
    <script>
        const btn = document.querySelector('button');

        btn.addEventListener('click', function () {
            console.log('button click 1');
        });  // 재활용 불가

        function btnClick () {
            console.log('button click 2');
        } // 재활용 가능

        btn.addEventListener('click', btnClick);

    </script>
</body>

이벤트 핸들러 프로퍼티 방식과 addEventListener 메서드 방식을 모두 사용하여 이벤트 핸들러를 등록하면?

 

    addEventListener 메서드 방식은 이벤트 핸들러 프로퍼티에 바인딩된 이벤트 핸들러에 아무 영향을 주지 않음
    따라서 버튼 요소에서 클릭 이벤트가 발생하면 2개의 이벤트 핸들러가 모두 호출

<body>
    <button>Click me!</button>
    <script>
        const btn = document.querySelector('button');
        
        // 이벤트 핸들러 프로퍼티 방식.
        btn.onclick = function () {
            console.log('[이벤트 핸들러 프로퍼티 방식] button click');
        }

        // addEventListener 메서드 방식.
        btn.addEventListener('click', function () {
            console.log('[addEventListner 메서드 방식] button click');
        });
    </script>

</body>

💫  addEventListener 메서드는 동일한 요소에서 발생한 동일한 이벤트에 대해 하나 이상의 이벤트 핸들러를 등록할 수 있음
<body>
<button>Click me!</button>
<script>
    const btn = document.querySelector('button');

    function btnClick () {
            console.log(`button click`);
    }

    btn.addEventListener('click', btnClick);
    btn.addEventListener('click', btnClick);

</script>
</body>

응용 예제
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script>

        document.addEventListener('DOMContentLoaded', () => {
            const h1 = document.querySelector('h1');
            let counter = 0;

            h1.addEventListener('click', function (event) { 
            // h1 태그에 click 이벤트가 발생할 때 실행할 함수.
                counter++;
                h1.textContent = `클릭 횟수: ${counter}`;
            });
        });
    </script>
    <style>
        h1 { /* 클릭을 여러 번 했을 때 글자가 선택되는 것을 막기 위한 스타일. 드래그가 안됨 */
            user-select: none;
            cursor: pointer;
        }
    </style>

</head>
<body>
    <h1>클릭 횟수: 0</h1>
</body>


(2) 이벤트 핸들러 제거

 

문서 객체.removeEventListener(이벤트 이름, 콜백 함수)

 

  👩🏻‍💻  addEventListener 메서드로 등록한 이벤트 핸들러를 제거하려면

        EventTarget.prototype.removeEventListener() 메서드를 사용 
  👩🏻‍💻  removeEventListener 메서드에 전달할 인수는 addEventListener 메서드와 동일
  👩🏻‍💻  addEventListener 메서드에 전달한 인수와 removeEventListener 메서드에 전달한 인수가 일치하지 않으면
        이벤트 핸들러가 제거되지 않음  ➡️ 
익명함수를 이벤트 핸들러로 등록한 경우에는 제거할 수 없음
       ⚡️ 단, 기명 이벤트 핸들러 내부에서 removeEventListener 메서드를 호출하여 이벤트 핸들러를 제거하는 것은 가능
            (이때 이벤트 핸들러는 단 한 번만 호출)

<body>
    <button>Click me!</button>
    <script>
        const btn = document.querySelector('button');

        const handleClick = () => console.log('button click');

        // 이벤트 핸들러 등록
        btn.addEventListener('click', handleClick);

        // 이벤트 핸들러 제거
        btn.removeEventListener('click', handleClick, true); // 실패
        btn.removeEventListener('click', handleClick); // 성공
    </script>
</body>

기명 이벤트 핸들러 내부에서 removeEventListener 메서드를 호출하여 이벤트 핸들러를 제거
<body>
<button>Click me!</button>
<script>

    const btn = document.querySelector('button');

    btn.addEventListener('click', function foo() {
        console.log('button click');

        // 이벤트 핸들러를 제거. 따라서 이벤트 핸들러는 단 한 번만 호출.
        btn.removeEventListener('click', foo);
    });

</script>
</body>

 

프로퍼티 방식으로 이벤트 핸들러 등록한 경우 removeEventListener 메서드로 제거 불가

 

    💫  프로퍼티에 'null' 할당하여 제거

<body>
    <button>Click me!</button>
    <script>
        const btn = document.querySelector('button');
        const handleClick = () => console.log('button click');

        // 이벤트 핸들러 프로퍼티 방식으로 이벤트 핸들러 등록
        btn.onclick = handleClick;

        // removeEventListener 메서드로 이벤트 핸들러를 제거할 수 없음.
        btn.removeEventListener('click', handleClick);

        // 이벤트 핸들러 프로퍼티에 null을 할당하여 이벤트 핸들러를 제거.
        btn.onclick = null;
    </script>
</body>

예제

 

<body>
    <button id="changeBtn">배경색 변경</button>
    <button id="resetBtn">배경색 초기화</button>
    <script>
        const changeBtn = document.querySelector('#changeBtn');
        const resetBtn = document.querySelector('#resetBtn');

        let i = 0;

        const bodyTag = document.querySelector('body');
        const color = ['red', 'orange', 'yellow', 'blue'];
        const handleColor = () => {
            bodyTag.style.backgroundColor = color[i++ % color.length];
        }

        changeBtn.addEventListener('click', handleColor);
        resetBtn.addEventListener('click', () => {
            changeBtn.removeEventListener('click', handleColor);
            bodyTag.style.backgroundColor = '';
        })
    </script>
</body>

 


응용 예제
<head>
    <script>

        document.addEventListener('DOMContentLoaded', () => {
            const h1 = document.querySelector('h1');
            const btnConnect = document.getElementById('connect');
            const btnDisconnect = document.getElementById('disconnect');
            const p = document.querySelector('p');

            let counter = 0;
            let isConnect = false; // 이벤트를 여러 번 연결되지 않게

            const listener = (event) => { // 이벤트를 제거하려면 이벤트 리스너를 변수 또는 상수로 가지고 있어야 함.
                h1.textContent = `클릭 횟수: ${counter++}`;
            }

            btnConnect.addEventListener('click', function () {
                if (isConnect === false) {
                    // 1. h1에 이벤트 리스너 연결
                    h1.addEventListener('click', listener);

                    // 2. btnConnect 버튼 안 보이도록
                    this.style.display = 'none';
                    btnDisconnect.style.display = 'block';

                    // 3. p의 내용을 '이벤트 연결 상태 : 연결'로 변경
                    p.textContent = '이벤트 연결 상태: 연결';

                    isConnect = true;
                }
            });

            btnDisconnect.addEventListener('click', function () {
                if (isConnect === true) {
                    // 1. h1에 이벤트 리스너 해제
                    h1.removeEventListener('click', listener);

                    // 2. btnDisconnect 버튼 안 보이도록
                    btnConnect.style.display = 'block'
                    this.style.display = 'none';

                    // 3. p의 내용을 '이벤트 연결 상태 : 해제'로 변경
                    p.textContent = '이벤트 연결 상태: 해제';

                    isConnect = false;
                }
            })

        });
    </script>
    <style>
        h1 {
            user-select: none;
            cursor: pointer;
        }
    </style>
</head>
<body>
    <h1>클릭 횟수: 0</h1>
    <button id="connect">이벤트 연결</button>
    <button id="disconnect">이벤트 제거</button>
    <p>이벤트 연결 상태: 해제</p>
</body>

 

 

 

 

 

 

 

[ 내용참고 : IT 학원 강의 및 책 '혼자 공부하는 자바스크립트' ]


1.  글자 조작하기

속성 이름 설명
문서 객체.textContent 입력된 문자열을 그대로 넣음
문서 객체.innerHTML 인력된 문자열을 HTML 형식으로 넣음

 

<head>
    <script>
        document.addEventListener('DOMContentLoaded', () => {
            const a = document.getElementById('a');
            const b = document.querySelector('#b'); // 아이디 선택자 사용.

            a.textContent = '<h1>textContent 속성</h1>';
            b.innerHTML = '<h1>innerHTML 속성</h1>';
        })
    </script>
</head>
<body>
    <div id="a"></div>
    <div id="b"></div>
</body>


2.  스타일 조작하기

 

👩🏻‍💻  자바스크립트의 style 속성들의 이름이 CSS에서 사용할 때와 차이가 없음
👩🏻‍💻  자바스크립트에서는 -가 연산자이고, 식별자에 사용할 수 없어서 두 단어의 조합은 캐멀 케이스로 표현

CSS 속성 이름 자바스크립트 style 속성 이름
background-color backgroundColor
text-align textAlign
font-size fontSize

 

💡  스타일을 조정하는 방법
       h1.style.backgroundColor      ▶️ 이 형태를 가장 많이 사용
        h1.style['backgroundColor']
        h1.style['background-color'

 

<head>
    <script>
        document.addEventListener('DOMContentLoaded', () => {
            const divs = document.querySelectorAll('body > div');

            divs.forEach((div, index) => { // div 개수 만큼 반복 출력.
                console.log(div, index);
                const val = index * 10; // index는 0부터 24까지 반복.
                div.style.height = `10px`; // 크기를 지정할 때는 반드시 단위를 붙여줘야 함.
                div.style.backgroundColor = `rgba(${val}, ${val}, ${val})`;
            })
        });
    </script>
</head>
<body>
    <!-- div 태그 25개 -->
    <div></div><div></div><div></div><div></div><div></div>
    <div></div><div></div><div></div><div></div><div></div>
    <div></div><div></div><div></div><div></div><div></div>
    <div></div><div></div><div></div><div></div><div></div>
    <div></div><div></div><div></div><div></div><div></div>
</body>

 


3.  속성 조작하기

👩🏻‍💻  문서 객체의 속성을 조작할 때는 다음과 같은 메소드를 사용

메소드 이름 설명
문서 객체.setAttribute(속성 이름, 값) 특정 속성에 값을 지정
문서 객체.getAttribute(속성 이름) 특정 속성을 추출

 

<head>    
    <script>
        document.addEventListener('DOMContentLoaded', () => {
            const rects = document.querySelectorAll('.rect'); // 클래스 선택자 이용.

           // for (let i = 0; i < rects.length; i++) {
           //     const width = (i + 1) * 100; // 100, 200, 300, 400의 너비를 가짐.
           //     const src = `http://placebear.com/${width}/250`;
           //     rects[i].setAttribute('src', src); // src 속성에 값을 지정.
           // }

           // foreach() 메서드로 동일한 작업
           rects.forEach((item, index) => {
               const width = (index + 1) * 100;
               const src = `http://placebear.com/${width}/250`;
               item.setAttribute('src', src); // src 속성에 값을 지정.
           })

        })
    </script>
</head>
<body>
    <img class="rect" alt="" src="">
    <img class="rect" alt="" src="">
    <img class="rect" alt="" src="">
    <img class="rect" alt="" src="">
</body>


예제
<head>
    <script>
        /*
        버튼을 클릭하면 버튼에 있는 색상으로 과일 목록이 글자색이 변하도록
         */
        document.addEventListener('DOMContentLoaded', () => {
            const btns = document.querySelectorAll('div button');
            const fruits = document.querySelectorAll('ul li');
            const colors = ['red', 'orange', 'yellow'];

            btns.forEach((item, index) => {
                item.addEventListener('click', () => {
                    fruits.forEach((item) => {
                        item.style.color = colors[index];
                    })
                })
            })

        })
    </script>
</head>
<body>
    <ul>
        <li id="apple">Apple</li>
        <li id="banana">Banana</li>
        <li id="orange">Orange</li>
    </ul>
    <div>
        <button>red</button>
        <button>orange</button>
        <button>yellow</button>
    </div>
</body>

 


4.  문서 객체 생성하기

document.createElement(문서 객체 이름)
부모 객체.appendChild(자식 객체)

    

📌  createElement()
    

    -  body 태그 내부에 있는 특정 문서 객체를 읽어들이고 조작하는 것도 가능하나 문서 객체를 생성하는 것도 가능
    -  문서 객체를 생성하고 싶을 때는 document.createElement() 메소드를 사용

📌  appendChild()


   -  문서 객체를 만든 후에는 '문서 객체를 추가'해야 함
   -  appendChild() 메소드를 활용하면 부모 객체 아래에 자식 객체를 추가할 수 있음
    

<script>
    // createElement() 메소드로 h1 태그를 생성하고, appendChild()를 사용하여 객체를 추가.
    document.addEventListener('DOMContentLoaded', () => {
        // 문서 객체 생성하기
        const header = document.createElement('h1');

        // 생성한 태그 조작하기
        header.textContent = '문서 객체 동적으로 생성하기';
        header.setAttribute('data-custom', '사용자 정의 속성');
        header.style.color = 'white';
        header.style.backgroundColor = 'black';
        console.log(header);

        // h1 태그를 body 태그 아래에 추가하기
        document.body.appendChild(header);
    })
</script>

 


5.  문서 객체 이동하기

👩🏻‍💻  appendChild() 메소드를 사용하면 문서 객체를 이동할 수도 있음
        ▶️  문서 객체를 다른 문서 객체에 추가하면 문서 객체가 이동

<head>
    <script>
        document.addEventListener('DOMContentLoaded', () => {
            // 문서 객체 읽어들이고 생성하기
            const divA = document.querySelector('#first'); // id 속성이 first인 태그를 반환
            const divB = document.getElementById('second'); // id 속성이 second인 태그를 반환

            const h1 = document.createElement('h1'); // h1 태그를 생성
            h1.textContent = '이동하는 h1 태그';

            // 서로 번갈아가면서 실행하는 함수를 구현
            const toFirst = () => {
                divA.appendChild(h1); // h1을 divA에 추가
                setTimeout(toSecond, 1000); // 1초 후에 toSecond() 함수를 실행
            }
            const toSecond = () => {
                divB.appendChild(h1); // h1을 divB에 추가
                setTimeout(toFirst, 1000);
            }
            toFirst();
        });
    </script>
</head>
<body>
    <div id="first">
        <h1>첫 번째 div 태그 내부</h1>
    </div>
    <hr>
    <div id="second">
        <h1>두 번째 div 태그 내부</h1>
    </div>

</body>

 


6.  문서 객체 제거하기

👩🏻‍💻  문서 객체를 제거할 때는 removeChild() 메소드를 사용

부모 객체.removeChild(자식 객체);

 

👩🏻‍💻  appendChild() 메소드 등으로 부모 객체와 이미 연결이 완료된 문서 객체의 경우 parentNode 속성으로
      부모 객체에 접근할 수 있으므로, 일반적으로 어떤 문서 객체를 제거할 때는 다음과 같은 형태의 코드 사용

 문서 객체.parentNode.removeChild(문서 객체);

 

<head>
    <script>
        document.addEventListener('DOMContentLoaded', () => {
            setTimeout(() => {
                const h1 = document.querySelector('h1');
                h1.parentNode.removeChild(h1);
            }, 3000);
        })
    </script>
</head>
<body>
   <hr>
   <h1>제거 대상 문서 객체</h1>
   <hr>
</body>


예제

 

<head>
    <style>
        * {
            margin: 0;
            padding: 0;
            list-style: none;
        }
    </style>
    <script>
        /*
        1. 버튼을 클릭하면 무지개색 li가 추가
        2. 같은 색깔의 li는 2개가 될 수 없음
         */
        document.addEventListener('DOMContentLoaded', () => {
            const btn = document.querySelector('button');
            const ulTag = document.querySelector('ul');
            const colors = ['red', 'orange', 'yellow', 'green', 'blue', 'indigo', 'violet'];

            let cnt = 0;
            btn.addEventListener('click', function () {
                const liTag = document.createElement('li');

                liTag.textContent = colors[cnt % colors.length];
                liTag.style.backgroundColor = colors[cnt++ % colors.length];
                liTag.style.color = 'white';

                if (cnt > colors.length) {
                    const firstLi = document.querySelector('ul li:nth-child(1)');
                    firstLi.parentNode.removeChild(firstLi);
                }
                ulTag.appendChild(liTag);
            });
        });
    </script>
</head>
<body>
    <button>무지개색 추가</button>
    <ul>

    </ul>
</body>

 

 

 

 

[ 내용참고 : IT 학원 강의 및 책 '혼자 공부하는 자바스크립트' ]


1.  문서 객체 모델 DOM  Document Object Model

👩🏻‍💻  문서 객체를 조합해서 만든 전체적인 형태를 말함

👩🏻‍💻  자바 스크립트를 사용하는 목적은 html을 다루는 것
        ▶️  자바 스크립트에서는 html 요소를 문서 객체 document object를 이용해 조작을 함

👩🏻‍💻  HTML 페이지는 코드를 위에서 아래로 차례대로 실행

        ➡️  body 태그 생성되기 이전인 head 태그에서 body 태그에 무언가 출력하려면 문제 발생

       ➡️  기본적으로 head 태그 내부에 script 태그를 배치하면 body 태그에 있는 문서 객체(요소)에 접근 불가

<head>    
    <script>
        const h1 = (text) => `<h1>${text}</h1>`;
    </script>
    <script>
        document.addEventListener('DOMContentLoaded', function () {
            document.body.innerHTML += h1('1번째 script 태그');
        });
    </script>
</head>
<body>

    <h1>1번째 h1 태그</h1>
    <script>
        document.body.innerHTML += h1('3번째 script 태그');
    </script>
    <h1>2번째 h1 태그</h1>

</body>

 


 

(1)  DOMContentLoaded 이벤트

💡  DOMContentLoaded 이벤트는 웹 브라우저가 문서 객체를 모두 읽고 나서 실행       
       ▶️  script 태그가 body 태그 이전에 위치해도 문제없이 코드 실행
<script>
    // DOMContentLoaded를 연결. DOMContentLoaded 상태가 되었을 때 콜백 함수를 호출
    document.addEventListener('DOMContentLoaded', () => {
        const h1 = (text) => `<h1>${text}</h1>`;
        document.body.innerHTML += h1('DocumentLoaded 이벤트 발생');
    });
</script>

📌  DOMContentLoaded 사용한 배경색 변경 예제
<head>
    <script>
        document.addEventListener('DOMContentLoaded', function () {
            const changeBtn = document.querySelector('#changeBtn');
            const resetBtn = document.querySelector('#resetBtn');

            let i = 0;

            const bodyTag = document.querySelector('body');
            const color = ['red', 'orange', 'yellow', 'blue'];
            const handleColor = () => {
                bodyTag.style.backgroundColor = color[i++ % color.length];
            }

            changeBtn.addEventListener('click', handleColor);
            resetBtn.addEventListener('click', () => {
                changeBtn.removeEventListener('click', handleColor);
                bodyTag.style.backgroundColor = '';
            })
        })
    </script>
</head>
<body>
    <button id="changeBtn">배경색 변경</button>
    <button id="resetBtn">배경색 초기화</button>
</body>

 


 

💡  addEventListener('이벤트', '콜백함수') 메소드
     -  document라는 문서 객체의 이벤트가 발생했을 때, 매개변수로 지정한 콜백 함수를 실행하라는 의미

 


(2) 문서 객체 가져오기

document.head / document.body / document.title

        
    👩🏻‍💻  head와 body 요소 내부에 다른 요소들은 다음과 같은 별도의 메소드를 사용해서 접근
         ⚡️  document.querySelector(선택자) : 요소를 하나만 추출
         ⚡️  document.querySelectorAll(선택자) : 선택자에 해당하는 모든 문서 객체를 배열로 가져옴
     👩🏻‍💻  선택자 부분에는 CSS 선택자를 입력

이름 선택자 형태 설명
태그 선택자 태그 특정 태그를 가진 요소를 추출
아이디 선택자 #아이디 특정 id 속성을 가진 요소를 추출
클래스 선택자 .클래스 특정 class 속성을 가진 요소를 추출
속성 선택자 [속성=값] 특정 속성 값을 갖고 있는 요소 추출
후손 선택자 선택자_A 선택자_B 선택자_A 아래에 있는 선택자_B 선택

 

<head>
    <script>
        document.addEventListener('DOMContentLoaded', () => {
            const header = document.querySelector('h1'); // 요소를 읽어들임. 제일 먼저 나오는 요소 하나만 가져옴.
            // 텍스트와 스타일을 변경.
            header.textContent = 'HEADERS';
            header.style.color = 'white';
            header.style.backgroundColor = 'black';
            header.style.padding = '10px';

            const headersAll = document.querySelectorAll('h2'); // 요소를 읽어들임.
            console.log(headersAll)
            headersAll.forEach((item) => { // 일반적으로 forEach() 메소드를 사용해서 반복을 돌림.
                item.textContent = 'headersAll';
                item.style.color = 'red';
                item.style.backgroundColor = 'black';
                item.style.padding = '20px';
            })

            // 1. for문을 사용해서 글자색을 빨강으로 변경
            for(let idx = 0; idx < headersAll.length; idx++) {
                headersAll[idx].style.color = 'red';
            }

            // 2. for in 문을 사용해서 글자색을 파랑으로 변경
            for(let idx in [...headersAll]) {
                headersAll[idx].style.color = 'blue';
            }

            // 3. for of 문을 사용해서 글자색을 주황으로 변경
            for(const i of headersAll) {
                i.style.color = 'orange';
            }

        })
    </script>
</head>
<body>
    <h1></h1>
    <h1>2</h1>
    <h2></h2>
    <h2></h2>
    <h2></h2>
    <h2></h2>
</body>

 

 

 

 

[ 내용참고 : IT 학원 강의 및 책 '혼자 공부하는 자바스크립트' ]


1.  형변환 Casting

· 변수 또는 상수의 타입을 다른 타입으로 변환하는 것

· 형변환 방법 ; (타입)피연산자

· float 타입의 값을 int 타입으로 변환할 때 소수점 이하의 값은 버림으로 처리됨

 

    ⚡️  자동 형변환 : 값의 범위가 작은 타입에서 큰 타입으로의 형변환은 생략가능

    ⚡️  명시적 형변환 : 변수의 자료형을 강제로 바꾸는 것 ▶️ 숫자크기 상관없이 앞에 형변환 해줘야 함

 
<기본형의 자동 형변환이 가능한 방향>

 

public class Etc0208 {

	public static void main(String[] args) {
		
		byte b = 10;
		int i = b;
	
		System.out.println("i=" + i); // 10
		System.out.println("b=" + b); // 10
		
		int i2 = 10;
		byte b2 = (byte)i2;

		System.out.println("i2=" + i2); // 10
		System.out.println("b2=" + b2); // 10

	}
}

 

public class Exma001 {

	public static void main(String[] args) {

		byte a = 127; // byte가 가질 수 있는 최대값
		int b = a; // 자동 형변환 (byte -> int)
		System.out.println(b); // 127
		
		float c = b; // 자동형변환 (int -> float) 값손실이 없기 때문.
		System.out.println(c); // 127.0
		
		//int d = c; // float 자료형을 int 변수에 대입하면 자동형변환이 안됨.

	}

}

 


문자열을 기본 타입으로 강제 타입 변환


  📌  String은 int나 char처럼 기본 자료 타입이 아닌 클래스의 객체 형태라서 일반적인 형변환과 다름

public class MyVar_09 {
    public static void main(String[] args) {
		
		String str = "1a";
		//int value = Integer.parseInt(str); // 문자열에 숫자외의 문자가 있으면 변환이 되지 않음
		
		// String -> byte
		String str1 = "10";
		byte value1 = Byte.parseByte(str1);
		System.out.println(value1); // 10
		
		// String -> short
		String str2 = "200";
		short value2 = Short.parseShort(str2);
		System.out.println(value2); // 200
		
		// String -> int
		String str3 = "300000";
		int value3 = Integer.parseInt(str3);
		System.out.println(value3); // 300000
		
		// String -> long
		String str4 = "400000000";
		long value4 = Long.parseLong(str4);
		System.out.println(value4); // 400000000
		
		// String -> float
		String str5 = "12.345";
		float value5 = Float.parseFloat(str5);
		System.out.println(value5); // 12.345
		
		// String -> double
		String str6 = "12.345";
		double value6 = Double.parseDouble(str6);
		System.out.println(value6); // 12.345
		
		// String -> boolean
		String str7 = "true";
		boolean value7 = Boolean.parseBoolean(str7);
		System.out.println(value7); // true
		
	}
}

 


기본 타입과 문자열 간의 변환


  📌  기본 타입의 값을 문자열로 변경하는 경우에는 String.valueOf() 메소드를 이용

String str = String.valueOf(기본타입값);
public class MyVar_10 {
	public static void main(String[] args) {
		
		// 문자열을 기본 타입으로 변환
		int value1 = Integer.parseInt("10");
		double value2 = Double.parseDouble("3.14");
		boolean value3 = Boolean.parseBoolean("true");
		
		System.out.println("value1 : " + value1); // value1 : 10
		System.out.println("value2 : " + value2); // value2 : 3.14
		System.out.println("value3 : " + value3); // value3 : true
		
		// 기본 타입을 문자열로 변환
		String str1 = String.valueOf(10);
		String str2 = String.valueOf(3.14);
		String str3 = String.valueOf(false);
		
		System.out.println("str1 : " + str1); // str1 : 10
		System.out.println("str2 : " + str2); // str2 : 3.14
		System.out.println("str3 : " + str3); // str3 : false
	}
}

 


연습 문제

 

   📌  'int result = '에 1) 변수 4개를 모두 사용하고 2) 사칙연산중 + 연산만 사용해서 9가 나오도록 코드를 완성

public class Ex_01 {
	public static void main(String[] args) {
		
		long var1 = 2L;
		float var2 = 1.8f;
		double var3 = 2.5;
		String var4 = "3.9";
		
		int result = (int)var1 + (int)(var2 + var3) + (int)Double.parseDouble(var4); 
        // 이 부분만 수정. 0대신 코드 입력.
		System.out.println(result); // 9
	}
}

 


2.  연산자  Operator

 

· 연산자 : 연산을 수행하는 기호

· 피연산자(operand) : 연산자의 작업 대상 (변수, 상수, 리터럴, 수식)

· 단항 연산자의 우선순위가 이항 연산자보다 높다.

· 단항 연산자와 대입 연산자를 제외한 모든 연산의 진행방향은 왼쪽에서 오른쪽

 

 

(1)  산술 연산자

 

    a) 사칙 연산자 :  +(덧셈), -(뺄셈), *(곱셈), /(나눗셈)

    b) 나머지 연산자 :  %  ▶️ a를 b로 나눈 후 나머지를 반환, 주로 짝수 홀수 구분에 사용

public class Exam004 {
	public static void main(String[] args) {
		
		int num1 = 10; // 10을 대입
		int num2 = 3; // 3을 대입
		
		System.out.println(num1 + num2); // 13
		System.out.println(num1 - num2); // 7
		System.out.println(num1 * num2); // 30
		System.out.println(num1 / num2); // 3
		System.out.println(num1 % num2); // 1
		System.out.println(num1 % 2); // 0
		System.out.println(num2 % 2); // 1
	}
}

 


 

(2) 논리부정 연산자 : !

 

    -  피연산자가 true이면 false를, false면 true를 결과로 반환

public class Exam006 {
	public static void main(String[] args) {
		
		boolean a = true;
		boolean b = false;
		boolean c = !b; // b의 값을 반대로 바꾸어 입력
	
		System.out.println(a); // true
		System.out.println(!a); // false
		
		System.out.println(b); // false
		System.out.println(c); // true
	}
}

 


(3) 정수와 실수 연산

 

    - 정수와 정수의 연산의 결과 값은 정수. 정수와 실수 연산의 결과 값은 실수 

public class MyVar_11 {
	public static void main(String[] args) {

		byte kor, math, eng;
		kor = 55;
		math = 99;
		eng = 87;
		
		int sum = kor + math + eng;
		System.out.println("총점 : " + sum); // 총점 : 241
		
		int avg_01 = sum /3;
		System.out.println("평균 : " + avg_01); // 평균 : 80
		
		double avg_02 = sum /3; // 정수 / 정수
		System.out.println("평균 : " + avg_02); // 평균 : 80.0 -> 정수 연산으로 정수 값이 나온 후에 실수에 저장.
		
		double avg_03 = (double)sum / 3; // 실수 / 정수
		System.out.println("평균 : " + avg_03); // 평균 : 80.33333333333333
		
		double avg_04 = sum / 3.0; // 정수 / 실수
		System.out.println("평균 : " + avg_04); // 평균 : 80.33333333333333
		
		double avg_05 = (double)sum / 3.0; // 실수 / 실수
		System.out.println("평균 : " + avg_05); // 평균 : 80.33333333333333
		
	}
}

 

 

 

 

[ 내용 참고 : IT 학원 강의 및 자바의 정석 3rd ]


1.  변수 variable 란?

 

👩🏻‍💻  단 하나의 값을 저장할 수 있는 메모리 공간

       ex. int age = 25  ▶️ 변수 age를 선언하고 25로 초기화 한다.

 

변수 명명 규칙

 

     a.  예약어 사용 x

     b.  숫자로 시작 x

     c.  특수문자는 '_'와 '$'만 가능

     d.  클래스 이름 첫 글자는 항상 대문자, 변수와 메서드의 첫 글자는 항상 소문자

     e.  여러단어로 이루어진 경우 첫 글자만 대문자

     f.   상수의 이름은 모두 대문자

정수형 변수 타입 범위 크기
byte -128~127 1 byte, 8bit
short -32,768 ~ 32,767 2 byte, 16bit
int 2,147,483,648 ~ 2,147,483,6647 4 byte, 32bit
long -9,223,372,036,854,775,808 ~ 9,223,372,036,854,775,807 8 byte, 64bit

 

💡  float : 소수점 7자리
💡  double : 소수점 15자리

 


2.  변수 기본형  Primitive type

(1) 논리형 ; boolean - true, false 값만 가짐 (1byte)

public class BooleanExample {
	public static void main(String[] args) {
		// boolean 형은 두가지 값만 존재 : true, false
		boolean stop = false;
		if(stop) {
			System.out.println("중지합니다.");
		} else {
			System.out.println("시작합니다.");
		}
	}
}
// 출력결과 : 시작합니다.
 

 

(2) 문자형 'char' (2byte)

 

     📁  char단 하나의 문자만 저장, 여러 문자를 저장 할려면 String 사용
     📁  char''(작은 따옴표)로만 묶임
     📁  String클래스, ""(큰 따옴표)로만 묶어야 함

 
public class Etc0201 {
	public static void main(String[] args) {
		// 문자를 숫자로
		char ch = 'A'; // char ch = '\u0041';로 바꿔 써도 같다.
		int code = (int)ch; // ch에 저장된 값을 int형으로 변환하여 저장한다.
		System.out.println(ch); // A
		System.out.println(code); // 65
	}
}

 

(3) 정수형 byte / short / int / long

      - long 접미사 ; l or L

 


 

(4) 실수형 float / double

      - float 접미사 ; f ( 기본 타입이 double 이기 때문에 안 붙이면 에러남)

 


※  아스키코드 
   미국정보교환표준부호, 또는 줄여서 ASCII는 영문 알파벳을 사용하는 대표적인 문자 인코딩이다. 아스키는 컴퓨터와 통신 장비 
   를  비롯한 문자를 사용하는 많은 장치에서 사용되며, 대부분의 문자 인코딩이 아스키에 기초를 두고 있다.
(출처 ; 위키백과)

※  유니코드   
   전 세계의 거의 모든 문자에 고유 숫자를 부여한 문자 집합

 


💡 데이터 단위 (출처; 삼성반도체 사이트)

3.  상수 constant 와 리터럴 literal 

 

(1) 상수

형식 : final 데이터 타입 상수명 = 값;

 

  · 변수와 달리 한 번 값을 저장하면 다른 값으로 변경할 수 없다. 대문자로 선언

  · 변수 타입 앞에 'final' 붙이면 된다.

public class Exam003 {
	public static void main(String[] args) {
		int a =3;
		System.out.println(a); // 3
		a = 4;
		System.out.println(a); // 4
		
		final double PI = 3.14;
		// PI = 3.15; // 에러발생
		System.out.println(PI); // 3.14 이 문장만 봐도 PI가 상수인걸 할 수 있도록 대문자로 작성.
	}
}

 


 

(2)  리터럴

 

· 문자 리터럴 : 작은따옴표로 문자 하나를 표현한 것  ▶️  ''안에 하나의 문자가 있어야 함

· 문자열 리터럴 : 큰 따옴표로 감싼 두 문자 이상  ▶️  "" 안에 아무런 문자도 넣지 않는 것 ok

· 덧셈 연산자는 피연산자 중 어느 한 쪽이 String이면 나머지 한 쪽을 먼저 String으로 변환한 다음 두 String을 결합한다.

    * 왼쪽에서 오른쪽 방향으로 연산을 수행

 

char sample = '\'' = ''';

 

public class MyVar_06 {
	public static void main(String[] args) {
		/* 문자열 표현 */
		char single = '\''; 
		String db1Quote = "\"Hello\""; // 겹따옴표를 출력하려면 이렇게 한다.
	    String root = "c:\\";
	    
	    System.out.println(single); // '
	    System.out.println(db1Quote); // "Hello"
	    System.out.println(root); // c:\
	    
	    char single2 = '"';
	    String single3 = "'";
	    String db1Quote2 = "'Hello'";
	    //String db1Quote3 = 'Hello';  // 에러
	    
	    System.out.println(single2); // "
	    System.out.println(single3); // '
	    System.out.println(db1Quote2); // 'Hello'
	}
}

 


4.  문자열 연산

 

'+' 연산자의 두 가지 기능


    1) 피연산자가 숫자일 경우에는 덧셈 연산
    2) 피연산자 중 하나라도 문자열이면 나머지 피연산자도 문자열로 자동 변환되어서 문자열 결합 연산을 수행

public class MyVar_07 {
	public static void main(String[] args) {
		// 숫자 결합 연산
		int value = 10 + 2 + 8;
		System.out.println("value : " + value); // 20
		
		
		// 문자 결합 연산
		String str1 = 10 + 2 + "8";
		System.out.println("str1 : " + str1); // 128 :
		// 연산자는 왼쪽에서 오른쪽으로 순서대로 실행이 되기 때문에
		// 12 + "8" 이 됨 
		
		String str2 = 10 + "2" + 8;
		System.out.println("str2 : " + str2); // str2 : 1028
		
		String str3 = "10" + 2 + 8;
		System.out.println("str3 : " + str3); // str3 : 1028
		
		String str4 = "10" + (2 + 8);
		System.out.println("str4 : " + str4); // str4 : 1010

	}

}

 


문자열 연산 예제
public class MyVar_08 {
	public static void main(String[] args) {

		String a = 7 + " ";
		String b = " " + 7;
		String c = 7 + "";
		String d = "" + 7;
		String e = "" + "";
		String f = 7 + 7 + "";
		String g = "" + 7 + 7;
		
		System.out.println(a); // 7
		System.out.println(b); //  7
		System.out.println(c); // 7
		System.out.println(d); // 7
		System.out.println(e); 
		System.out.println(f); // 14
		System.out.println(g); // 77
	}
}

 

 

 

 

 

[내용 출처 : 자바의정석 및 학원강의]


1.  타이머 timer 함수  

🐰  특정 시간 이후에 콜백함수를 호출할 수 있는 함수

함수 이름 설명
setTimeout(함수, 시간) 특정 시간 후에 함수를 한 번 호출
setInterval(함수, 시간) 특정 시간마다 함수를 호출

 

<script>
    setTimeout(function () {
        console.log(`2초 후에 실행됩니다.`);
    }, 2 * 1000); // 시간의 기초단위는 밀리 초 단위.

    let count = 0;
    setInterval(() => {
        console.log(`2초마다 실행됩니다.(${count}번째)`);
        count++;
    }, 2 * 1000);
</script>

 


타이머 함수를 종료하고 싶은 경우

 

함수 이름 설명
clearTimeout(타이머_ID) setTimeout() 함수로 설정한 타이머를 제거
clearInterval(타이머_ID) setInterval() 함수로 설정한 타이머를 제거

 

🐰  타이머 ID는 setTimeout()과 setInterval() 함수를 호출할 때 리턴 값으로 나오는 숫자

<script>
    let count = 0;
    let id = setInterval(() => { // setInterval은 반환형이 있는 함수이기 때문에 변수에 저장 가능
        console.log(`1초마다 실행됩니다(${count}번째)`);
        count++;
    }, 1000);

    setTimeout(() => {
        console.log('타이머를 종료합니다.');
        clearInterval(id);
    }, 5 * 1000); // 5초후 종료
</script>

 


응용 문제 - 정지 & 시작버튼

 

<head>
    <style>
        * {
            padding: 0;
            margin: 0;
        }

        #numb {
            width: 100vw;
            height: 400px;
            display: flex;
            justify-content: center;
            align-items: center;
            font-size: 300px;
        }

        #box {
            display: flex;
            justify-content: center;
            align-content: center;
        }

        button {
            width: 50px;
            height: 20px;
            margin: 0 10px;
        }

    </style>

    <script>
        /* '정지' 버튼을 클릭하면 정지 */
        const rainbow = ['red', 'orange', 'yellow', 'green', 'blue', 'indigo', 'violet'];
        let count = 1;
        const timer = function () {
            document.querySelector('div').innerHTML = String(count);
            document.querySelector('div').style.color = rainbow[count % rainbow.length];
            count++;
        };

        let id = setInterval(timer, 1000);

        const stopTimer = function () {
            clearInterval(id);
        };

        const reStart = function () {
            id = setInterval(timer, 1000);
        };
    </script>
</head>
<body>
    <div id="numb">0</div>
    <div id="box">
        <button onclick="stopTimer()">정지</button>
        <button onclick="reStart()">재시작</button>
    </div>
</body>

 

 


2.  기본 매개변수


🐰  매개 변수에 기본 값을 지정, 매개 변수가 들어오지 않는 경우에 기본 값으로 대체
🐰  기본 매개 변수와 일반 매개 변수를 섞어서 사용할 경우에는 기본 매개 변수가 오른쪽으로 가야됨

함수이름(매개변수, 매개변수=기본값, 매개변수=기본값)
<script>

  const earnings = function (name, wage = 8590, hours = 40) {
    console.log(`# ${name}님의 급여 정보`);
    console.log(`- 시급: ${wage}원`);
    console.log(`- 근무 시간: ${hours}시간`);
    console.log(`- 급여: ${wage * hours}원`);
    console.log('');
  }

  // 최저 임금으로 최대한 일하는 경우
  earnings('smith');

  // 시급 1만원으로 최대한 일하는 경우
  earnings('adam', 10000);

  // 시급 1만원으로 52시간 일한 경우
  earnings('tom', 10000, 52);
</script>


응용 문제
<script>
    // 년도를 인수로 전달하지 않은 경우에는 현재 년을 기본값으로 함.
    // 윤년을 확인하는 함수를 정의 - 정수 연도를 입력받아서 윤년의 여부를 불린형으로 반환.
    const isLeapYear = function (year = new Date().getFullYear()) {
        const isLeapYear = (year % 4 === 0) && (year % 100 !== 0) || (year % 400 === 0);
        return isLeapYear;
    }

    console.log(`올해는 윤년일까? === ${isLeapYear()}`); 
</script>

 


3.  즉시 호출 함수  Immediately-invoked function expression

(function () { })();


 🐰  선언과 동시에 함수가 실행되며 보통은 함수명 없이 사용하기 때문에 재호출이 안됨
 🐰  변수의 충돌을 막기 위해 사용. 재사용을 위해서 함수를 만드는게 아닌 변수의 충돌을 막기 위해 블록화를 하는 목적으로 사용

💡  자바 스크립트에서 선언적 함수보다 익명함수를 생성하고 바로 호출하는 패턴이 많은 이유 

 

       -  이름 충돌 방지
       -  다른 프로그램에 비해 자바 스크립트는 라이브러리를 많이 사용하고
           한 페이지에 사용하는 프로그램이 여러 개의 파일로 나누어져 있거나 여러 개로 분리되어 있어서
           다른 프로그래밍 언어보다 이름 충돌되는 경우가 많음
       -  익명함수를 사용해서 이름이 중복되는 함수를 만드는 것을 방지

<!-- 이름 충돌 문제 발생 -->
<!-- 다른 곳에서 가져온 자바스크립트 코드 -->
<script>
    let pi = 3.14;
    console.log(`파이 값은 ${pi}입니다.`);
</script>

<!-- 내가 만든 자바스크립트 코드 -->
<script> // Uncaught SyntaxError: Identifier 'pi' has already been declared
    let pi = 3.141592; // 중복 선언
    console.log(`파이 값은 ${pi}입니다.`);
</script>

<script>
    // 1. 재호출이 안되는 형태
    (function() {
        life();
    })();
    function life() {
        console.log(`즉시 실행 함수1`); // 즉시 실행 함수1
    }

    // 1) 익명함수처럼 보이니까 즉석 실행 함수를 변수에 저장한다면?
    let instant = (function() {
        console.log('즉시 실행 함수2'); // 즉시 실행 함수2
    })();
    console.log(typeof instant); // undefined. 변수에 할당되지는 않고 실행만 됨.
    // instant(); // Uncaught TypeError: instant is not a function

    // 2) 선언적 함수처럼 이름을 지정하면 재실행 되지 않을까?
    (function instant3rd () {
        console.log(`즉시 실행 함수3`);
    })();

    // instant3rd(); // Uncaught ReferenceError: instant3rd is not defined

    // 2. 재실행이 가능한 경우
    let instant4th;
    (instant4th = function() {
        console.log('즉시 실행 함수4'); // 즉시 실행 함수4
    })();
    console.log(typeof instant4th); // function
    instant4th(); // 즉시 실행 함수4
</script>

 

 


스코프 scope : 변수가 존재하는 범위   

 

   -  같은 단계의 스코프에서 동일한 이름의 변수가 있으면 충돌
   -  스코프 단계를 변경하는 방법은 중괄호를 사용해서 블록을 만들거나, 함수를 생성해서 블록을 만듦
   -  블록 내부에서 같은 이름으로 변수를 선언하면 변수가 외부 변수와 충돌하지 않고

       외부 변수를 가려서 내부 블록에서 선언한 변수만 볼 수 있음
   -  블록이 다른 경우 내부 변수가 외부 변수를 가리는 현상을 섀도잉 shadowing 이라고 함

💡  블록({}) 생성으로 이름 충돌 문제를 해결하는 방법은  구 브라우저나, var 키워드 사용하는 경우에는 사용할 수 없어서 대체재로 즉시 호출 함수를 사용
<script>
    let pi = 3.14;
    console.log(`파이 값은 ${pi}입니다.`); // 파이 값은 3.14입니다.

    // 블록을 사용한 스코프 생성
    {
        let pi = 3.141592; // 블록에서 선언한 변수는 블록 안에서만 사용 가능
        console.log(`파이 값은 ${pi}입니다.`); // 파이 값은 3.141592입니다. 블록에서 pi가 선언되지 않았다면 전역을 들고 옴.
    }

    console.log(`파이 값은 ${pi}입니다.`); // 파이 값은 3.14입니다.

    // 함수 블록을 사용한 스코프 생성
    function sample() {
        let pi = 3.141592;
        console.log(`파이 값은 ${pi}입니다.`);
    }
    sample(); // 파이 값은 3.141592입니다.
    console.log(`파이 값은 ${pi}입니다.`); // 파이 값은 3.14입니다.
</script>

 


var 에서 블럭 사용과 즉석 실행 함수
<script>
    var animal = 'dog';
    console.log(animal); // dog

    {
        var animal = 'cat';
        console.log(animal); // cat
    }
    console.log(animal); // cat. 블록에서 사용했지만 블록 밖에서 변수 사용이 됨

    var animal = 'dog';
    console.log(animal); // dog
    (function () {
        var animal = 'cat';
        console.log(animal); // cat
    })();

    console.log(animal); // dog. 즉시 호출 함수의 경우에는 함수 블럭 안에서만 변수의 범위가 제한 됨.
</script>

 


블록 사용으로 이름 충돌을 막을 수 없는 경우 즉시 호출 함수 사용
<!-- 다른 곳에서 가져온 자바스크립트 코드 -->
<script>
    let pi = 3.14;
    console.log(`파이 값은 ${pi}입니다.`); // 파이 값은 3.14입니다.
</script>

<!-- 내가 만든 자바스크립트 코드 -->
<script>
    /* 즉시 호출 함수를 사용해 변수 이름 충돌 문제를 해결 */
    (function () {
        let pi = 3.141592;
        console.log(`파이 값은 ${pi}입니다.`); // 파이 값은 3.141592입니다.
    })();
</script>

 


4.  엄격 모드  strict mode

🐰  'use strict' 문자열을 읽은 후 부터는 코드를 엄격하게 검사
🐰  초기의 자바 스크립트는 간단한 보조 프로그램을 만드는게 목적이라 어느 정도 오류가 있어도 정상적으로 작동.
      하지만 이후에 자바 스크립트의 사용이 활발해 지고, 규모가 있는 프로그램을 만들기 위해서는 코드의 오류를 엄격하게 검사를 해야돼서 엄격 모드 사용

      🥕  즉시 호출 함수를 만들고, 이 블록의 가장 윗쪽에 엄격 모드를 적용하는 경우가 많음
              ▶️  이렇게 하면 해당 블록 내부에서만 엄격 모드가 적용
 

 사용예:
    (function () {
        'use strict';
        문장;
        문장
     }) ();
<script>
    /* 변수를 선언하지 않아도 사용이 됨. */
    data = 10;
    console.log(data); // 10
</script>
<script>
    'use strict';
    data = 10; // Unresolved variable or type data
    console.log(data); // 10
</script>

 

 

 

 

[ 내용 참고 : IT 학원 강의 및 책 'Do it HTML+CSS+자바스크립트 웹 표준의 정석' ]

+ Recent posts