본문 바로가기

3. HTML | CSS | Javascript

4/11(화) IT K-DT(29일차) / 24.이벤트~30.예외처리


24. 이벤트(Event)

    24-1. 이벤트의 정의

    24-2. 이벤트 타입(event type)

    24-3. 이벤트 타겟(event target)

    24-4. 이벤트 리스너(event listener)

    24-5. 이벤트 객체(event object)

    24-6. 이벤트 전파(event propagation)

 

25. 이터레이터(Iterator)와 이터러블(Iterable)

    25-1. 이터레이터(Iterator)

    25-2. 이터러블(Iterable)

 

26. 제너레이터(Generator)

 

27. 스프레드(spread) 연산자

 

28. 세트(set)

 

29. 맵(map)

 

30. 예외처리

 

예제


24. 이벤트(Event)

24-1. 이벤트의 정의

웹 페이지에서 어떤 일이 발생했음을 알리는 신호
웹 페이지에 사용된 Javascript는 발생한 상황에 반응하여 특정 동작을 수행할 수 있음.
(Javascript : 비동기식 이벤트 중심의 프로그래밍 모델)

 


1. <input type="button" onclick="sendit()" value="확인">
    # button: Event target. 여기서는 '버튼'.
    # onclick: Event type. 클릭 시 이벤트가 발생함.
    # sendit(): Event listener. 이벤트가 발생하게 되면 연결되어 행동함.

2. <button type="button" onclick=sendit()"> 확인 </button>


1과 2는 동일한 결과를 출력.

24-2. 이벤트 타입(event type)

발생한 이벤트의 종류를 나타내는 문자열로 이벤트명이라고도 함.
키보드, 마우스, HTML DOM, window 객체 등을 처리하는 이벤트 제공.
MDN에서 다양한 이벤트에 대해 검색할 수 있음.
(https://developer.mozilla.org/ko/docs/Web/API/Event)

 마우스 이벤트: 마우스와 관련된 이벤트로 클릭, 드래그, 오버 등이 있음.
 키보드 이벤트: 키보드와 관련된 이벤트로 키를 누르거나 뗄 때 발생.
 폼 이벤트: 폼과 관련된 이벤트로 제출(submit), 재설정(reset) 등이 있음.
 윈도우 이벤트: 브라우저 윈도우와 관련된 이벤트로 로드(load), 언로드(unload) 등이 있음.
 네트워크 이벤트: 네트워크와 관련된 이벤트로 AJAX 요청 등의 완료(complete) 이벤트가 있음.
 미디어 이벤트: 미디어(오디오, 비디오)와 관련된 이벤트로 재생(play), 일시정지(pause) 등이 있음.

 

예) '문자열을 클릭하세요' 텍스트를 클릭하면 문자가 변경.



<script>

    window.onload=function(){           // window.onload: 웹 페이지의 컨텐츠가 로드되었을 때 실행되는 이벤트.
        const text = document.getElementById('text');
        text.innerHTML = "<b style='color:deeppink; '>HTML 문서가 모두 로드되었습니다! </b>";
    }                // innerHTML: 동적으로 HTML 코드를 생성, 수정
    
    function changeText(el){
        el.innerHTML = "<b style='color:deepskyblue; '> 문자열이 변경되었습니다! </b>";
    }
    
</script>


<body>
    <p id="text"></p>
        <p onclick="changeText(this)">문자열을 클릭하세요</p> // this는 p 태그 그 자체임.
          // 해당 문자열을 클릭하면 el을 담은 changeText로 넘어가서 innerHTML함수가 실행됨.
</body>


이벤트타입

문자열을 클릭하세요

24-3. 이벤트 타겟(event target)

이벤트가 발생한 HTML 요소. 이벤트가 일어날 객체를 의미. 
이벤트 타겟은 이벤트가 등록된 대상 요소와 일치하거나, 대상 요소의 자식 요소 중 하나가 될 수 있음.

 

예를 들어, 사용자가 버튼을 클릭하면 이벤트 타겟은 그 버튼이 됨.

버튼의 자식 요소인 아이콘을 클릭한다면, 이벤트 타겟은 아이콘이 됨.


24-4. 이벤트 리스너(event listener)

이벤트가 발생했을 때 실행되는 '함수'.
'이벤트 핸들러(Handler)'라고도 부름.
지정된 타입의 이벤트가 특정 요소에서 발생하면 웹 브라우저는 그 요소에 등록된 이벤트 리스너를 실행.

    이벤트 등록
    객체.addEventListener  (Event type, Event listener)

    이벤트 제거
    객체.removeEventListener  (Event type, Event listener)

예) 'click' 이벤트를 처리하는 이벤트 리스너의 등록


const btn = document.getElementById('#Button');

btn.addEventListener ('click', function(event) {
  console.log('Button clicked');
});

 

예)


 <script>
        window.onload = function(){
            const btn = document.getElementById('eventBtn');
            btn.addEventListener('click', clickBtn); 
          // clickBtn을 Callback함수로 이용할 예정.
            btn.addEventListener('mouseover', mouseOverBtn); 
         // eventListner를 여러 개 줄 수도 있음. mouseOverBtn을 Callback함수로 이용할 예정.
            btn.addEventListener('mouseout', mouseOutBtn); 
        }

        function clickBtn(){
            document.getElementById('text').innerHTML = '<b>버튼을 클릭했어요</b>';
        }

        function mouseOverBtn(){
            document.getElementById('text').innerHTML = '<b>버튼위에 커서가 올라갔어요</b>';
        }

        function mouseOutBtn(){
            document.getElementById('text').innerHTML = '<b>버튼 밖으로 커서가 나갔어요</b>';
        }

        function delEvent(){ // event listener를 모두 해제하는 function
            const btn = document.getElementById('eventBtn');
            btn.removeEventListener('click', clickBtn);
            btn.removeEventListener('mouseover', mouseOverBtn);
            btn.removeEventListener('mouseout', mouseOutBtn);
            document.getElementById('text').innerHTML = '<b> 이벤트 리스너가 모두 삭제되었어요.</b>';
        }
</script>


<body>
    <h2>이벤트리스너</h2>
    <p><button id="eventBtn">이벤트버튼</button>
        <button id="delBtn" onclick="delEvent()">이벤트삭제버튼 </button></p>
        <p id="text"></p>
</body>
이벤트리스너

이벤트리스너

24-5. 이벤트 객체(event object)

이벤트가 발생할 때 생성되는 객체로, 해당 타입의 이벤트에 대한 상세 정보를 저장하고 있음.
모든 이벤트 객체는 이벤트의 타입을 나타내는 'type property'와 이벤트 대상을 나타내는 'target property'를 갖고 있음.
이벤트 객체를 이벤트 리스너가 호출할 때 인수로 전달.


 function sendit(e) {         
 }
 // 매개변수 e를 받아 e가 객체로의 활동이 가능함. (e.target(button), e.type(click)의 사용이 가능.)

 <input type="button" onclick="sendit()" value="완료"> 
 // sendit()을 위의 function으로 호출.


 <script>
        window.onload = function() {
            const btn = document.getElementById('btn');
            btn.addEventListener('click', clickBtn);
            
        }

        function clickBtn(e){
            console.log(e.target);
            console.log(e.target.id);
            console.log(e.target.value);
            console.log(e.type);
        }
</script>

<body>

    <button type="button" id="btn" value="확인">확인</button>

</body>

24-6. 이벤트 전파(event propagation)

이벤트가 발생한 요소에서 상위 요소까지 이벤트가 전달되는 과정.
document 객체나 html 문서의 요소에서 이벤트가 발생하면 대상 요소를 결정하기 위해 이벤트 전파가 일어남.

버블링 전파방식
자식에서 부모로 이벤트를 전파.

캡처링 전파방식
부모에서 자식으로 이벤트를 전파.

이벤트 전파 중지
이벤트객체명.stopPropagation()

 

이벤트 기본 동작 취소

이벤트객체명.preventDefault()

 


 
 <style>
        #divBox {
            width: 100%;
            height: 300px;
            border: 3px solid red;
        }
        #pBox {
            width: 70%;
            height: 150px;
            border: 1px solid blue;
        }
        #spanBox {
            border: 3px solid gold;
        }
 </style>
    

 <script>

        window.onload = function(){

             // 버블링 전파방식
             document.getElementById('divBox').addEventListener('click', clickDiv);
             document.getElementById('pBox').addEventListener('click', clickP);
             document.getElementById('spanBox').addEventListener('click', clickSpan);

             // 캡쳐링 전파방식
             document.getElementById('divBox').addEventListener('click', clickDiv, true);
             document.getElementById('pBox').addEventListener('click', clickP, true);
             document.getElementById('spanBox').addEventListener('click', clickSpan, true);
        }
        
        function clickDiv(e) {
            document.getElementById('text').innerHTML += "<span style='color:red;'>div를 클릭했어요</span><br>" 
          // click할때마다 생성되는 문장을 누적해서 이어주는 함수
        } 

        function clickP(e) {
            document.getElementById('text').innerHTML += "<span style='color:blue;'>P를 클릭했어요</span><br>" 
         // click할때마다 생성되는 문장을 누적해서 이어주는 함수
        }

        function clickSpan(e) {
            document.getElementById('text').innerHTML += "<span style='color:gold;'>span를 클릭했어요</span><br>" 
          // click할때마다 생성되는 문장을 누적해서 이어주는 함수
        } // Div > P > Span의 영역 구조이므로, Span을 클릭하면 P, Div도 모두 문장이 생성.
        
</script>


<body>
    <div id="divBox">
        <p id="pBox">
            <span id="spanBox">클릭
            </span>
        </p>
    </div>

    <p id="text"></p>

</body>

이벤트전파

이벤트전파

클릭


25. 이터레이터(Iterator)와 이터러블(Iterable)

자바스크립트에서 데이터 컬렉션을 다룰 때 사용하는 개념.

 

25-1. 이터레이터(Iterator)

반복처리가 가능한 객체. 이터러블에서 값을 하나씩 가져올 수 있는 객체.
내부적으로 IteratorResult 객체인 next() 메서드를 호출하여 다음 값을 가져올 수 있음.
계속 진행한다는 의미의 'value'와 반복이 끝났다는 의미의 'done'이라는 property를 가진 객체를 반환.

 


25-2. 이터러블(Iterable)

반복 가능한 객체.
Symbol.Iterator라는 이터레이터(Iterator) 객체를 반환하는 메서드를 가짐.

이터러블(Iterable)이 이터레이터(Iterator)에 포함된 구조.
배열(Array), 문자열(String), 맵(Map), 셋(Set) 등이 포함
for문으로 반복이 가능.


 <script>
        const arr = [1, 2, 3, 4, 5];
        
        console.log(arr.values()); // Array Iterator 출력. Array는 Iterable한 객체이기 때문.
        console.log(arr.entries()); // Array Iterator 출력. 
        console.log(arr.keys()); // Array Iterator 출력. 


        const iterator = arr.values(); // arr을 뽑아서 iterator에 저장함.

        while (true) {
            const item = iterator.next();
            if(item.done) break;
                console.log(item.value); // 만약 item이 done이면 break하고, value면 계속 진행하라는 의미. // 1 2 3 4 5 출력
        }

        for (let item of arr){
            console.log(item);
        } // 1 2 3 4 5 출력

 </script> 

 <script>

    function iter(){
        let index = 0;
        let data = [1,2,3,4];
        return {
            next(){
                if (index < data.length){
                    return {value:data[index++], done:false};
                } else {
                    return {value:undefined, done:true};
                }
            }
        }
    }

    let i = iter();
    
    console.log(i.next()); // done:false value:1
    console.log(i.next()); // done:false value:2
    console.log(i.next()); // done:false value:3
    console.log(i.next()); // done:false value:4
    console.log(i.next()); // done:true value:undefined

 </script>

26. 제너레이터(Generator)

실행을 멈추었다가 나중에 다시 접근할 수 있는 특이한 형태의 함수.
나중에 다시 접근하기 위해 context(변수)를 저장된 상태로 남겨둠.
이터레이터(Iterator) 프로토콜을 따름.

제너레이터 함수 내부에서 yield 키워드를 사용하면 해당 지점에서 실행을 멈출 수 있음.

비동기 프로그래밍에서 많이 사용.


    function* 제너레이터명( ) {

    }

 <script>

        function* multipleGenerator(){
            try {                                 // try-catch의 구조. python의 try-except문과 유사.
                for(let i=0; i<10; i++){
                    console.log(i);        // 0
                    yield i ** 2;
                }
            } catch(error){
                console.log(error);
            }
        }

        const multiple multipleGenerator();

        let next = multiple.next();
        console.log(next.value, next.done); // 0 0 false

        next = multiple.next();
        console.log(next.value, next.done); // 1 1 false

        next = multiple.next();
        console.log(next.value, next.done); // 2 4 false

        next = multiple.next();
        console.log(next.value, next.done); // 3 9 false

        next = multiple.next();
        console.log(next.value, next.done); // 4 16 false
        
</script>

27. 스프레드(spread) 연산자

주로 배열이나 객체를 추가하거나 병합하는 등 확장할 때 사용하는 연산자.
객체에서 스프레드 연산자를 사용하면, 객체의 모든 속성을 새로운 객체로 확장할 수 있음.
모든 Iterable은 spread가 될 수 있음.
순회가능한 데이터는 펼쳐질 수 있음.

    function 함수명(...Iterable)
        [...Iterable]
        {...obj}

 예)


    const obj1 = { a:1, b:2, c:3 };
    const obj2 = { ...obj1, d:4, e:5, f:6 };
    console.log(obj2); // { a:1, b:2, c:3, d:4, e:5, f:6 }


스프레드 연산자의 사용으로 구조분해할당이 가능함.


const fruits = ['🍈','🍉','🍊','🍋','🍌','🍍'];
const [fruit1, fruit2, fruit3, fruit4, fruit5, fruit6] = fruits; // fruits의 과일 그림을 각각의 문자에 자동으로 할당해줌.
const [fruit1, fruit2, ...others] = fruits; // 이런식으로 ...others 를 사용해도 정상적으로 출력 가능.

 


 <script>

        function add(num1, num2, num3){
            return num1 + num2 + num3;
        }

        const nums = [10, 20, 30];
        console.log(add(nums[0],nums[1], nums[2])); // 60
        console.log(add(...nums)); // 60

        function sum(num1, num2, ...nums){
            console.log(nums); // 7 10 4 8 9 (num1과 num2를 제외한 nums)
        }

        sum(1,3,7,10,4,8,9);

</script>


        const fruits1 = ['🍑','🍉'];
        const fruits2 = ['🍋','🍍'];
        let arr = fruits1.concat(fruits2);
        console.log(arr); // 0:'🍑' 1:'🍉' 2:'🍋' 3:'🍍'

        arr = [...fruits1, ...fruits2];
        console.log(arr); // 0:'🍑' 1:'🍉' 2:'🍋' 3:'🍍'

        arr = [...fruits1, '🍔', ...fruits2];
        console.log(arr); // 0:'🍑' 1:'🍉' 2:'🍔' 3:'🍋' 4:'🍍'

        const apple = {name:'김사과', age:20, address:{si:'seoul'}};
        console.log(apple);

        const apple_update = {...apple, job:'프로그래머'}; 
        console.log(apple_update); // 기존의 apple을 가져오면서, job이라는 property를 새로 추가함.

        const fruits = ['🍑','🍉','🍔','🍋','🍍']
        const [fruit1, fruit2, ...others] = fruits;

        console.log(fruit1); // 🍑
        console.log(fruit2); // 🍉
        console.log(others); // 🍔 🍋 🍍


        const point = [1, 2];
        const [x, y, z=0] = point;
        console.log(x); // 1
        console.log(y); // 2
        console.log(z); // 0

        function sendEmoji(){
            return ['🍑','🍉','🍔','🍋','🍍'];
        }

        const [peach, watermelon, hambug, lemon, pineapple] = sendEmoji(); 
// sendEmoji()가 위의 return되는 array에 자동으로 할당됨.

        console.log(peach); // 🍑
        console.log(watermelon); // 🍉
        console.log(hambug); // 🍔
        console.log(lemon); // 🍋
        console.log(pineapple); // 🍍

        // function display(apple) {
        //     console.log('이름', apple.name); 
        //     console.log('나이', apple.age); 
        //     console.log('직업', apple.job); 
        // } // 1번 함수
        
        function display({name, age, job}) {
            console.log('이름', name); 
            console.log('나이', age); 
            console.log('직업', job); 
        } // 2번 함수

        console.log(apple_update);
        display(apple_update); 
// apple_update를 2번 함수로 전달하여 name, age, job을 출력할 수 있도록 함. 1번함수 = 2번함수.

const {name, age, pet='루시', job:hobby} = apple_update;
// apple_update에 pet은 없어서 기본값으로 저장, job은 다르지만 hobby로 저장.


        console.log(name); // 김사과
        console.log(age); // 20
        console.log(pet); // 루시
        console.log(hobby); // 프로그래머 // console.log(job); 으로 쓰면 안된다. 오류 발생.

        const component = {name:'Button', styles:{size:20, color:'black'}};

        function changeColor({styles: {color}}){
            console.log(color);
        }

        changeColor(component); // black

28. 세트(Set)

중복되지 않은 유일한 값들의 집합
요소 순서에 의미가 없음
인덱스로 요소에 접근할 수 없음.
교집합, 차칩합, 합집합, 여집합 등을 구현


    const 세트명 = new Set([요소1, 요소2, 요소3 ...]);

 <script>

        const set = new Set([1,2,3,4,5]);
        
        console.log(set); // 1 2 3 4 5
        
        console.log(set.size); // 5

        console.log(set.has(2)); // true
        console.log(set.has(10)); // false

        set.forEach((item)=>console.log(item)); // 1 2 3 4 5
        // forEach(값, 인덱스, 배열) 의 형태로, 인덱스와 배열의 위치는 생략이 가능.

        for (let value of set){
            console.log(value);
        } // 1 2 3 4 5

        set.add(6); // 6을 추가
        console.log(set);
        set.add(6); // 6을 재추가를 시도할 수 없음. set이므로 중복된 값이 없기때문.

        set.delete(6); // 6을 삭제
        console.log(set);

        set.clear(); // 전부 삭제.
        console.log(set);

        const obj1 = {name:'사과', emoji:'🍎', price:1000};
        const obj2 = {name:'바나나', emoji:'🍌', price:2000};
        const set2 = new Set([obj1, obj2]);
        console.log(set2); 
// value: {name: '사과', emoji: '🍎', price: 1000}, value: {name: '바나나', emoji: '🍌', price: 2000}

        obj1.price = 1500;
        set2.add(obj1);
        console.log(set2); 
// value: {name: '사과', emoji: '🍎', price: 1500}, value: {name: '바나나', emoji: '🍌', price: 2000}

        const obj3 = {name:'사과', emoji:'🍎', price:1000};
        set2.add(obj3);
        console.log(set2);
// value: {name: '사과', emoji: '🍎', price: 1500}, value: {name: '바나나', emoji: '🍌', price: 2000}, 
   value: {name: '사과', emoji: '🍎', price: 1000}

 </script>

29. 맵(map)

Key, value로 이루어진 데이터 집합의 자료구조


  const 맵이름 = new Map ( [ [ '키1' , '값1' ] , [ '키2' , '값2' ] , ... ] ) ;

예)


        const map = new Map([
            ['apple','🍎'], ['banana','🍌']
        ]);

        console.log(map);

 

map.size
예) map의 크기를 확인.

 
 console.log(map.size); // 2

 

map.has()
예) map에서 key 존재를 확인.


 console.log(map.has('apple')); // true
 console.log(map.has('banana')); // true
 console.log(map.has('orange')); // false. 'orange'라는 key는 없음.

 

map.forEach()
map도 iterable한 객체이므로 forEach의 사용이 가능함.

예) map에서 순회를 진행


 map.forEach((value, key) => console.log(key, value)); // apple 🍎, banana 🍌

 

map.get()

예) map에서 검색을 진행


 console.log(map.get('apple')); // 🍎
 console.log(map.get('banana')); // 🍌
 console.log(map.get('orange')); // undefined

 obj = {'apple':'🍎', 'banana':'🍌'}
 console.log(obj.get('apple')); // undefined. obj에는 get()이 없으므로 해당 값을 찾을 수 없음.
 console.log('obj: '+ obj['apple']); // obj: 🍎
 console.log('obj: '+ obj.apple); // obj: 🍎
 console.log('map: '+ map['apple']); // map: undefined
 console.log('map: '+ map.get('apple')); // map: 🍎
 console.log('map: '+ map.apple); // map: undefined

 

map.set()
예) map에 orange를 추가.


 map.set('orange', '🍊');

 console.log(map);

 

map.delete()
예) map에 orange를 삭제.


 map.delete('orange', '🍊');

 console.log(map);

 

map.clear()

예) map의 data를 전부삭제.


 map.clear();

 console.log(map);

 

30. 예외처리

try-catch-finally 문을 사용하여 처리.


try {
    예외가 발생할 것으로 예상되는 문장;
    ...
    ...
catch (error 객체) {
    예외가 발생했을 때 처리할 문장;
    ...
    ...
finally {
    예외와 관계없이 무조건 실행할 문장;
    ...
}

 

예)


        function readFile(path){                     // path가 없다면 error를 발생하는 함수 설정.
            throw new Error('파일 경로를 찾을 수 없음.');
            return '파일 경로를 참조하여 파일을 생성함.'
        }

        function processFile(path){
            let content;
            try {
                content = readFile(path);
            } catch(error) {
                console.log(error);
                content = '기본내용';
            } finally {
                console.log('에러의 발생 여부와 관계없이 실행할 문장을 작성했음.')
            }
            const result = '결과: ' + content;
            return result;
        }

        const result = processFile('경로');
        console.log(result);

 

예)


        function func1() {                                                // #4. func1()의 console문 실행.
            console.log('func1이 호출되었어요');
            throw new Error('에러발생');                          // #5. Error 발생
        }

        function func2(){                                                 // #3. 해당 func2()이 실행되면 바로 위의 구문이 실행됨.
            } try {
                func1();
            } catch(error) {                                                  // #6. Error 처리
                console.log('예외처리완료');
                throw error;                                                 // #7. Error 발생
            }
        }

        function func3(){                                                  // #2. 해당 func3()이 실행되면 try 안의 바로 위의 구문이 실행됨.
            } try {
                func2();
            }catch(error){                                                   // #8. Error 처리
                console.log('여기에서 예외처리 또 완료');  // #9. console문 실행.
        }

        func3();                                                                // #1. 해당 func3()을 실행.
        console.log('프로그램이 정상적으로 종료되었습니다.');   //#10. console문 실행.

예제

예제1

버튼 2개를 아래와 같이 만들고, 각각의 버튼을 눌렀을 때 console에 출력하는 문서를 만들어보자.
단, 이벤트 객체를 이용하여 버튼을 구별할 것.
버튼1:  '버튼1이 눌렸어요'
버튼2:  '버튼2가 눌렸어요'

 

window.onload = function(){
    버튼과 이벤트리스너 세팅
}
function clickBtn(e){
    버튼을 구별하여 버튼의 출력을 결정
}

 



 <script>
        window.onload = function(){
            const btn1 = document.getElementById('btn1');
            const btn2 = document.getElementById('btn2');

            btn1.addEventListener('click', clickbtn);
            btn2.addEventListener('click', clickbtn);
            btn3.addEventListener('click', (e) => {           // 화살표함수를 사용하여 e라는 익명의 함수를 사용하는 방법.
                console.log(`e.target.id: ${e.target.id}`);
                console.log('버튼3이 눌렸어요');
            });
        }

        function clickbtn(e){
            switch(e.target.id){
                case 'btn1':
                    console.log('버튼1이 눌렸어요');
                    break;
                case 'btn2':
                    console.log('버튼2가 눌렸어요');
                    break;
            }
        }
</script>


<body>
    <h2>예제1</h2>
    <input type="bvutton" id="btn1" value="버튼1">
    <input type="bvutton" id="btn2" value="버튼2">
    <input type="bvutton" id="btn3" value="버튼3">
</body>

예제2

주어진 배열에서 set을 이용하여 중복을 제거해보자 
 const fruits = ['🍎','🍊','🍎','🍉','🍌','🍓','🍌','🍈','🍋','🍈'];


const fruits = ['🍎','🍊','🍎','🍉','🍌','🍓','🍌','🍈','🍋','🍈'];

    function removeDuplication(arr){
        return [...new Set(arr)];
    }
    console.log(removeDuplication(fruits));

예제3

 주어진 두 set의 공통된 아이템만 담고 있는 세트를 생성해보자
 const set1 = new Set([1,2,3,4,5]);
 const set2 = new Set([1,2,3]);


    const set3 = new Set([1,2,3,4,5]);
    const set4 = new Set([1,2,3]);

    function findIntersection(set1, set2){
        return new Set([...set3].filter((item) => set2.has(item)))
    }
    console.log(findIntersection(set3,set4));