상세 컨텐츠

본문 제목

JavaScript 6일차

카테고리 없음

by teminam 2023. 4. 14. 16:53

본문

이벤트(Event)
- 웹 브라우저가 알려주는 HTML 요소에 대한 사건이 발생
- 웹 페이지에 사용된 자바스트립트는 발생한 이벤트에 반응하여 특정 동작을 수행할 수 있음
- 자바스크립트는 비동기식 이벤트 중심의 프로그래밍 모델

    <input type="button" onclick = "sendit()" value="확인">
                -------  -------    -------- 
              이벤트타겟  이벤트타입  이벤트리스너

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

이벤트타입(Event Type)
- 발생한 이벤트의 종류를 나타내는 문자열로 이벤트명이라고도 함
- 키보드, 마우스, HTML DOM, window 객체... 등을 처리하는 이벤트 제공
https://developer.mozilla.org/ko/docs/Web/API/Event

이벤트타겟(Event Target)
- 이벤트가 일어날 객체를 의미

 

 

Event - Web API | MDN

Event 인터페이스는 DOM에서 발생하는 이벤트를 나타냅니다.

developer.mozilla.org

 

 

<!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>이벤트타입</title>
    <script>
        window.onload = function(){
            const text = document.getElementById('text')
            text.innerHTML = "<b style='color:deeppink;'>HTML 문서가 모두 로드되었습니다!</b>";
        }
        function changeText(el){
            el.innerHTML = "<b style='color:deepskyblue;'>문자열이 변경되었습니다!😋</b>";
        }
    </script>
</head>
<body>
    <h2>이벤트타입</h2>
    <p id="text"></p>
    <p onclick="changeText(this)">문자열을 클릭하세요</p>
</body>
</html>

 

 

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

    이벤트 등록
    객체.addEventListener(이벤트타입, 이벤트리스너)

    이벤트 제거
    객체.removEventListener(이벤트타입, 이벤트리스너)

 

<!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>이벤트리스너</title>
    <script>
        window.onload = function(){
            const btn = document.getElementById('eventBtn')
            btn.addEventListener('click', clickBtn)
            btn.addEventListener('mouseover', mouseOverBtn)
            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(){
            const btn = document.getElementById('eventBtn')
            btn.removeEventListener('click', clickBtn)
            btn.removeEventListener('mouseover', mouseOverBtn)
            btn.removeEventListener('mouseout', mouseOutBtn)
            document.getElementById('text').innerHTML = '<b>이벤트 리스너가 모두 삭제되었어요</b>'
        }
    </script>
</head>
<body>
    <h2>이벤트리스너</h2>
    <p><button id="eventBtn">이벤트버튼</button> <button id="delBtn" onclick="delEvent()">이벤트 삭제버튼</button></p>
    <p id="text"></p>
</body>
</html>

 

이벤트 객체(Event Object)
- 특정 타입의 이벤트와 관련이 있는 객체
- 이벤트 객체는 해당 타입의 이벤트에 대한 상세 정보를 저장하고 있음
- 모든 이벤트 객체는 이벤트의 타입을 나타내는 type 프로퍼티와 이벤트 대상을 나타내는 target 프로퍼티를 가지고 있음
- 이벤트 객체를 이벤트 리스너가 호출할 때 인수로 전달

    function sendit(e){
        // e.target(button), e.type(click)
    }

    <input type="button" onclick="sendit()" value="완료">

문제.
버튼 2개를 아래와 같이 만들고 각 버튼을 누르면 콘솔에 출력하는 문서를 만들어보자. (단, 이벤트 객체를 이용하여 버튼을 구별함)

버튼1을 클릭 -> 버튼 1이 눌렸어요
버튼2을 클릭 -> 버튼 2가 눌렸어요

window.onload = function(){
    버튼과 이벤트리스너 세팅!
}

function clickBtn(e){
    버튼을 구별하여 버튼의 출력을 결정
}

 

<!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>이벤트 객체1</title>
    <script>
        window.onload = function(){
            const btn = document.getElementById('btn')
            btn.addEventListener('click', clickBtn)
        }
        function clickBtn(e){
            console.log(e.target)           // <button type="button" id="btn">확인</button>
            console.log(e.target.id)        // btn
            console.log(e.target.value)     // 확인
            console.log(e.type)             // click
        }
    </script>
</head>
<body>
    <h2>이벤트 객체1</h2>
    <button type="button" id="btn" value="확인">확인</button>
</body>
</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>이벤트 객체2</title>
    <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) => {
                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>
</head>
<body>
    <h2>이벤트 객체2</h2>
    <input type="button" id="btn1" value="버튼1">
    <input type="button" id="btn2" value="버튼2">
    <input type="button" id="btn3" value="버튼3">
</body>
</html>

 

이벤트 전파(Event Propagation)
- 이벤트가 발생했을 때, 브라우저가 이벤트 리스너를 실행시킬 대상 요소를 결정하는 과정
- document 객체나 html 문서의 요소에서 이벤트가 발생하면 대상 요소를 결정하기 위해 이벤트 전파가 일어남

 

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

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

이벤트 전파를 막는 방법
이벤트객체명.stopPropagation()

<!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>이벤트 전파</title>
    <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);    // 캡처링은 뒤에 true만 붙여주면 됨
            // document.getElementById('pBox').addEventListener('click', clickP, true);
            // document.getElementById('spanBox').addEventListener('click', clickSpan, true);  // div부터 실행됨

            function clickDiv(e){
                document.getElementById('text').innerHTML += "<span style='color:red;'>div를 클릭했어요</span><br>";
            }
            function clickP(e){
                document.getElementById('text').innerHTML += "<span style='color:blue;'>P를 클릭했어요</span><br>";
            }
            function clickSpan(e){
                // e.stopPropagation();
                document.getElementById('text').innerHTML += "<span style='color:gold;'>span을 클릭했어요</span><br>";
            }
        }
    </script>
</head>
<body>
    <h2>이벤트 전파</h2>
    <div id="divBox">
        <p id="pBox">
            <span id="spanBox">
                클릭
            </span>
        </p>
    </div>
    <p id="text"></p>
</body>
</html>



이터레이터(Iterator)
- 반복 처리가 가능한 객체
- 내부적으로 next() 메서드를 가지며, next() 메서드는 IteratorResult 객체 value와 done이라는 프로퍼티를 가진 객체를 반환해야 함

이터러블(Iterable)
- 반복이 가능한 객체
- Symbol.Iterator 메서드가 있어야 하며, Symbol.Iterator는 이터레이터 객체를 반환해야 함
- String, Array, Map, Set .. 등 객체
- for 문법으로 반복이 가능

<!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>이터러블</title>
</head>
<body>
    <h2>이터러블</h2>
    <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())
        console.log(i.next())
        console.log(i.next())
        console.log(i.next())
    </script>
</body>
</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>이터러블</title>
</head>
<body>
    <h2>이터러블</h2>
    <script>
        const arr = [1,2,3,4,5]
        console.log(arr.values())   // Array Iterator {}
        console.log(arr.entries())  // Array Iterator {}
        console.log(arr.keys())     // Array Iterator {}

        const iterator = arr.values()
        while(true){
            const item = iterator.next()
            if(item.done) break;
            console.log(item.value)
        }
        console.log('---------')

        for(let item of arr){
            console.log(item)
        }
        </script>
</body>
</html>

제너레이터(Generator)
- 실행을 멈췄다가 나중에 다시 접근할 수 있는 특이한 형태의 함수
- 나중에 다시 접근하기 위해 context(변수)를 저장된 상태로 남겨둠
- 이터레이터를 좀 더 유연하게 사용할 수 있음
    function* 제너레이터명(){

    }

 

 

<!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>제너레이터</title>
</head>
<body>
    <h2>제너레이터</h2>
    <script>
        function* multipleGenerator(){
            try{
                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 false
        next = multiple.next()
        console.log(next.value, next.done)    
        next = multiple.next()
        console.log(next.value, next.done)    
        next = multiple.next()
        console.log(next.value, next.done)    
    </script>
</body>
</html>



스프레드(Spread) 연산자 -> 전개구문
- 모든 Iterable은 Spread가 될 수 있음
- 순회가능한 데이터는 펼쳐 질 수 있음 

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

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

add(10, 20, 30)

const nums = [10, 20, 30]
add(nums[0], nums[1], nums[2])
add(...nums)

구조분해할당
const fruits = ['🍗', '🍖', '🍠', '🥂']
const [fruit1, fruit2, fruit3, fruit4] = fruits
const [fruit1, fruit2, ...others] = fruits  // others안에 고구마랑 건배가 들어감

✔ 참고!
const point = [1, 2]
const [x, y, z=0] = point

 

<!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>스프레드</title>
</head>
<body>
    <h2>스프레드</h2>
    <script>
        function add(num1, num2, num3){
            return num1+num2+num3
        }

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

        function sum(num1, num2, ...nums){
            console.log(nums)
        }
        sum(1, 3, 7, 10, 4, 8, 9)
        console.log('--------')
       
        const fruits1 = ['🍓', '🍌']
        const fruits2 = ['🍒', '💩']
        let arr = fruits1.concat(fruits2)
        console.log(arr)
        arr = [...fruits1, ...fruits2]
        console.log(arr)
        arr = [...fruits1, '✨', ...fruits2]
        console.log(arr)
        console.log('--------')

        const apple = {name: '김사과', age:20, address: {si: 'seoul'}}
        console.log(apple)
        const apple_update = {...apple, job: '프로그래머'}
        console.log(apple)
        console.log(apple_update)       // 새로운걸 만들어서 붙였음        
        console.log('--------')
       
        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)
        console.log(y)
        console.log(z)
        console.log('--------')
       
        function sendEmoji(){
            return ['🍈', '🍊', '🌼', '🍆']
        }
       
        const [banana, watermelon, berry, orange] = sendEmoji()
        console.log(banana)
        console.log(watermelon)
        console.log(berry)
        console.log(orange)
        console.log('--------')
       
        // function display(apple){
            //     console.log('이름', apple.name)
            //     console.log('나이', apple.age)
            //     console.log('직업', apple.job)
            // }
           
            function display({name, age, job}){
                console.log('이름', apple.name)
                console.log('나이', apple.age)
                console.log('직업', apple.job)
            }
           
            console.log(apple_update)
            display(apple_update)       // {name: '김사과', age: 20, address: {…}, job: '프로그래머'}
            console.log('--------')
           
            const {name, age, pet='루시', job: hobby} = apple_update    // pet은 없지만 기본값으로 저장
            console.log(name)
            console.log(age)
            console.log(pet)
            console.log(hobby)  // job으 hobby로 넣는다.
            console.log('--------')

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

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

        changeColor(component);

            // 코드 받기 에러남
        </script>
</body>
</html>

 

 


세트(Set)
- set 객체는 중복되지 않은 유일한 값들의 집합
- 요소 순서에 의미가 없음
- 인덱스로 요소에 접근할 수 없음
- 교집합, 합집합, 차집합, 여집합 등을 구현

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

문제1.
주어진 배열에서 중복을 제거해보자!
(단, set을 이용하여 중복제거)

const fruits = ['🍎', '🍅', '🍎', '🌽', '🍓', '🌽', '🍈', '🍋', '🍈', '🍒]

문제2.
주어진 두 세트의 공통된 아이템만 담고 있는 세트를 생성해보자

const set1 = new Set([1,2,3,4,5])
const set2 = new Set([1,2,3])

맵(map)
- Key, Value로 이루어진 데이터 집합의 자료구조

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

 

<!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></title>
</head>
<body>
    <h2></h2>
    <script>
        const map = new Map([
            ['apple', '🍎'], ['banana', '🍌']
        ])

        console.log(map)    // Map(2) {'apple' => '🍎', 'banana' => '🍌'}

        // 사이즈 확인
        console.log(map.size)       // 2

        // 키 존재 확인
        console.log(map.has('apple'))   // true
        console.log(map.has('banana'))  // true
        console.log(map.has('orange'))  // false

        // 순회(이터러블 객체)
        map.forEach((value, key) => console.log(key, value))        
        // apple 🍎
        // banana 🍌

        // 데이터 찾기
        console.log(map.get('apple'))   //  🍎
        console.log(map.get('banana'))  // 🍌
        console.log(map.get('orange'))  // undefined

        obj =  {'apple': '🍎', 'banana': '🍌'}
       //  console.log(obj.get('apple'))
        console.log('obj: ' + obj['apple'])
        console.log('obj: ' + obj.apple)
        console.log('--------')

        console.log('map: ' + map['apple'])
        console.log('map: ' + map.get('apple'))
        console.log('map: ' + map.apple)

        // 추가
        map.set('orange', '🍊')
        console.log(map)        // {'apple' => '🍎', 'banana' => '🍌', 'orange' => '🍊'}

        // 삭제
        map.delete('orange')
        console.log(map)        // Map(3) {'apple' => '🍎', 'banana' => '🍌', 'orange' => '🍊'}

        // 전부삭제
        map.clear()
        console.log(map)    // Map(0) {size: 0}
    </script>
</body>
</html>

 

✔ 주석(comments)
// 한줄짜리 주석
/* ~ */  여러줄 주석
/** */  JSDoc 주석

 

<!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>세트</title>
</head>
<body>
    <h2>세트</h2>
    <script>
        const set = new Set([1,2,3,4,5])
        console.log(set)    // Set(5) {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))    // 실제 들어있는 값들을 찍어낼 수 있음

        for(let value of set.values()){
            console.log(value)
        }

        set.add(6)
        console.log(set)        // Set(6) {1, 2, 3, 4, 5, …}[[Entries]]0: 11: 22: 33: 44: 55: 6size: 6[[Prototype]]: Set
       
        set.add(6)
        console.log(set)        // 추가 안됨

        set.delete(6)
        console.log(set)        // Set(5) {1, 2, 3, 4, 5}

        set.clear()
        console.log(set)        // Set(0) {size: 0}

        const obj1 = {name:'사과', emoji:'🍓', price:1000}
        const obj2 = {name:'바나나', emoji:'🍌', price:2000}
        const set2 = new Set([obj1, obj2])
        console.log(set2)
       
        obj1.price = 1500
        set2.add(obj1)
        console.log(set2)
       
        const obj3 = {name:'사과', emoji:'🍓', price:1000}
        set2.add(obj3)
        console.log(set2)
        console.log('-------')
   
        // 문제1. 주어진 배열에서 중복을 제거해보자! (단, set을 이용하여 중복제거)
        const fruits = ['🍎','🍊','🍎','🍉','🍌','🍓','🍌','🍈','🍋','🍈'];

        function removeDuplcation(arr){
            return [...new Set(arr)];
        }

        console.log(removeDuplcation(fruits));
        console.log('------------');

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

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

        console.log(findIntersection(set3, set4));
    </script>
</body>
</html>

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

 

Event - Web API | MDN

Event 인터페이스는 DOM에서 발생하는 이벤트를 나타냅니다.

developer.mozilla.org

 

 

 

<!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>예외처리1</title>
</head>
<body>
    <h2>예외처리1</h2>
    <script>
        /**
         * JSDOC 사용법
         * 주어진 매개변수 경로에 의한 파일을 만들고 반환함
         * @param {*} path 문자
         * @returns 파익객체
         */
        function readFile(path){      
            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)

        // Error: 파일 경로를 찾을 수 없음
        // at readFile (11. 예외처리1.html:19:19)
        // at processFile (11. 예외처리1.html:26:27)
        // at 11. 예외처리1.html:37:24

       
    </script>
</body>
</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>예외처리2</title>
</head>
<body>
    <h2>예외처리2</h2>
    <script>
        function func1(){
            console.log('func1이 호출되었어요!')
            throw new Error('에러발생!')
        }

        function func2(){
            // try{
                func1()
            // }catch(error){
            //     console.log('예외처리 완료')
            //     throw error
            // }
        }

        function func3(){
            // try{
                func2()
            // }catch(error){
            //     console.log('여기에서 예외처리 또 완료!')
            // }
        }

        func3()
        console.log('프로그램이 정상적으로 종료되었습니다!')
        console.log('------------------')


        function func1(){
            console.log('func1이 호출되었어요!')
            throw new Error('에러발생!')        // 억지로 에러 발생
        }

        function func2(){
            try{
                func1()
            }catch(error){      // 위에서 에러가 발생하여, 에러처리가 되어있으므로
                console.log('예외처리 완료')
            //    throw error
            throw error     // 한 번더 예외 발생
            }
        }

        function func3(){
            try{
                func2()
            }catch(error){
                console.log('여기에서 예외처리 또 완료!')       // 여기에서 cath문으로 또 에러처리
            }
        }

        func3()
        console.log('프로그램이 정상적으로 종료되었습니다!')
       
    </script>
</body>
</html>