배움 __IL/TIL 1기

TIL : 93번째- 230419 [4-3-수]

Mo_bi!e 2023. 4. 19. 18:13

I. JS : ES6  

1. Symbol

(1) 들어가며

1)

프로그래밍에서 약속은 곧 인터페이스이다

이것을 심볼로 약속한다는것의 의미이다

 

자료형 정의가 불가능한 JS는 그 약속을 심볼을 이용하는거야

let s = Symbol();
let s1 = Symbol();

console.log(s == s1);

false가 출력된다.

Symbol()은 프로퍼티가 중복되지못하는것이 용도중 하나이기 때문에 다를수 밖에 없다.

 

(2) symbol을 이용한 인터페이스 정의

1) 인터페이스로 정의 해보기(객체 형식으로 여러개)

{
//인터페이스 정의
    let examInterface = {
        total : Symbol(),
        avg : Symbol()
    };

//클래스 구현
    class Exam{
        constructor(){
        this.kor = 20;
        this.eng = 30;
        this.math = 40;
        }
    
	//인터페이스 구현
    total(){
        return this.kor + this.eng + this.math;
    }

    avg(){
        return this.total()/3;
    }
    }

    let exam = new Exam();
    exam.total();
    let result = exam[examInterface]();
    console.log(result);

}

let result = exam[examSymbol.total](); 에러

이렇게 나와!

total을 이용하려면 한번에 total까지 접근해서 이용해야해!

내가 함수를 정의했는데, 정의한것을 구현했는지 확실히 하려면 그 이름으로 함수를 정의해야해

 

2) interface 사용의 올바른 예

//symbol을 이용한 interface 정의
{
    // let examInterface = {
    let examSymbol = {
        total : Symbol(),
        avg : Symbol()
    };

    class Exam{
        constructor(){
        this.kor = 20;
        this.eng = 30;
        this.math = 40;
        }
        [examSymbol.total](){
            return this.kor + this.eng + this.math;
        }
        avg(){
            return this.total() / 3;
        }
    }

    let exam = new Exam();
    // exam.total();
    let result = exam[examSymbol.total]();
    console.log(result);

}

[examSymbo.total]() 을 한순간 exam.total()로는 호출할 수없다. 

이런경우 프로퍼티 symbol에 대해서 호출방법은 대괄호([]) 를 반드시 이용해야한다.

interface대신 symbol이라는 말을 쓰면 돼

 

(2) 인터페이스(심볼)로 이터레이터 구현하기

1) 이터레이터 구현

//==========================================
// iterator인터페이스(심볼)을 구현하기
{
    let lotto = {
        
        values(){
            let nums = [5,29,44,31];
            let index = 0;
            return{
                next(){
                    return{
                        done : false,
                        value : nums[index++]
                    }
                }
            }
        }
    };

    let it = lotto.values();

    for(let n of it)
        console.log(n); //이터러블 하지않음 exam은...

    // console.log("-----------------");

    // for(let n of lotto)
    //     console.log(n);

    // console.log("-----------------");

}

log에 이터러블하지않다고 출력이 된다.

사실 이미 이터러블 하게 꾸몄고 lotto 자체가 그러한 속성을 충분히 가지고 있다.

 

values()의 경우 각자 순회하는 경우는 가능하다

2) 이터레이션 프로토콜 부합 객체 출력하기 - 1

{
    let lotto = {
        
        //이터레이터를 구현현한것
        values(){
            let nums = [5,29,44,31];
            let index = 0;
            return{ //이터레이터 부분
                next(){
                    return{
                        done : index==4? true:false,
                        value : nums[index++]
                    }
                }
            }
        }
    };

    let it = lotto.values();
    // console.log(it.next().value);
    // console.log(it.next().value);
    // console.log(it.next().value);
    // console.log(it.next().value);
    for(let n of it)
        console.log(n);
//------------------------------
    let ar = [12,5,5,34,2];
    let it2 = ar.values();
    for(let n of it2)
        console.log(n); //출력성공함
}

for(let n of it) 부분 출력이 나오기 전 log 각 부분은 충분히 출력이 된다.

하지만 아래 오류와 같이 it 를 for-of문을 쓰면 이터러블 하지않다. lotto 통채로 반복문에 넣어주어야한다.

첫번째 log(n)은 이터러블 하지않는거야

이런경우에 이터레이터를 써야해 for-of 에서는 이터레이터가 와야한다는거야

3) 이터레이터 프로토콜 부합객체 출력하기 -2

{
    let lotto = {
        
        //이터레이터를 구현현한것
        [Symbol.iterator](){
            let nums = [5,29,44,31];
            let index = 0;
            return{ //이터레이터 부분
                next(){
                    return{
                        done : index==4? true:false,
                        value : nums[index++]
                    }
                }
            }
        }
    };

    // let it = lotto[Symbol.iterator]();
    // console.log(it.next().value);
    // console.log(it.next().value);
    // console.log(it.next().value);
    // console.log(it.next().value);
    for(let n of lotto)
        console.log(n);

    // let ar = [12,5,5,34,2];
    // let it2 = ar.values();
    // for(let n of it2)
    //     console.log(n);


}

이렇게 바로 lotto를 for-of에 넣으면 lotto자체가 이터러블한 것을 가지고있기 때문에 바로 이용이 가능하다

 

이터레이터가 아닌것을 이터러블하게 하고싶다. 이런것을 하고싶은데 너무 불편해 구현을 좀더 쉽게할 수없을까?

그래서 나온게 제너레이터야! 제너레이터는 이터레이터를 구현해주는 생성기야!

 

2. 제너레이터

(1) 들어가며

1) 들어가며

인터페이스를 이해하고 제너레이터를 생각하는것이 바람직하다

제너레이터란 이터레이션 프로토콜을 부합하는 어터러블을 구현한다. 또한 이는 비동기처리에 유용하다.

 

(2) 제너레이터

1) 구현하기

 

제너레이터함수는 function*로 구현한다

그리고 하나의상의 yield를 포함한다 (실행범위 지정)

//---- iterator구현을 쉽게 해주는 생성기 (Generators)------
{
    let lotto = {
        //이터레이터를 구현현한것
        *[Symbol.iterator](){
            let nums = [5,29,44,31];
            let index = 0;
            yield nums[index++];
            yield nums[index++];
            yield nums[index++];

// //이제 이런것들 구현할 필요가 없어 !!!!!!!!!
            // return{ //이터레이터 부분
            //     next(){
            //         return{
            //             done : index==4? true:false,
            //             value : nums[index++]
            //         }
            //     }
            // }
        }
    };

    for(let n of lotto)
        console.log(n);

    console.log("------------");

}

*제너테레이터야! 내가 이제 이 함수를 이터러블하게 쓰겠다는 의미야!

 

yield로 하면은 하나씩 나오는거야 이런경우 for문으로 한번에 할 수있어

 

2) yield 를 일반 for문으로

    //바보식 방법
    let lotto = {
        //이터레이터를 구현현한것
        *[Symbol.iterator](){
            let nums = [5,29,44,31];
            let index = 0;

            for(let i = 0 ; i<nums.length ; i++){
                yield nums[i];
            }
        }
    };

    for(let n of lotto)
        console.log(n);

    console.log("------------");

}

반복문을 이용해서 가능하다

즉 yield로 매번 특정 인덱스에 맞춰어서 까지 실행되고나서, 일시 중단된다.

 

3) yield 를 일반 for-of문으로

    let exam = {
        kor : 10,
        eng : 39,
        math : 20,

        //이렇게 만들면 돼
        *[Symbol.iterator](){
            yield this.kor;
            yield this.eng;
            yield this.math;
        }
    };

    for(let n of exam){
        console.log(n);
    }

    console.log("-------------");

yield를 하면 호출지점을 지정하는 역할을 한다. **

이것은 제너레이터 실행을 중지하거나 재개하는데 이용된다. 

 

4) 제너레이터의 시사점

이터레이터 구현한다는것은 직접구현하기 보다는 제러레이터 구현이 바람직하다

 

3. 기타

(1) 컴프리헨션

1)

es6에 있지만 바벨에서는 지원하지않는거

글자를 자르는것을 한다는거야

 

(2) 유니코드

1)

html에 선언한 유니코드에 영향을 받는다는 의미야

utf-8 일때

{
    console.log("abcd".length);
    console.log("𠮷".length);
    console.log("김밥레코드".length);


    console.log("-------------");
}

- 주로 정규식일 때 쓰는건데, 주요하게 쓰일 때에는 크롤링 할 때이다

 

(3) 정규식

1) 정규식 표현방법 6가지와 휴대전화번호 정규식 표현

// 문자 코드와 RegExp 검색 
{
    console.log("abcd".length);
    console.log("𠮷".length);
    console.log("김밥레코드".length);

    let phone = "010-1234-2122"; //패턴? 상수? => 상수
    // let exp = "010-????-????"; // => 패턴 을 만족하는 변화문자열

    // let exp = "010-[0-9][][][][]-[][][][]"; //1번
    // let exp = "010-\d[][][][]-[][][][]"; //2번
    // let exp = "010-\d{4}-\d{4}"; //3번
    let exp = "01[016789]-\d{3,4}-\d{4}"; //4번

    const exp1 = new RegExp("01[016789]-\d{3,4}-\d{4}"); //5번
    const exp2 = /^01[016789]-\d{3,4}-\d{4}$/; //이렇게 new 하지않고 간단하게 가능하다. //6번
    //그리고 앞 뒤에 시작과 끝을 잡는 ^ 과 $ 를 해주어야해!

    let tmp = exp2.test(phone); //정규식 만족하는지 여부
    console.log(tmp);

    console.log("-------------");
}

정규식의 표현방식은 여러가지야 6가지 정도 돼! (1 ~ 6번)

이런 경우에 test()를 하면 정규식이 부합하는지에 대해서 볼 수있어

test() : 부핮하지 않는경우 false 출력

2) 정규식 부합하는지 확인하기

정규식의 종류는 다 아는데 어떻게 조합하느냐가 문제야!

 

각각의 경우 직접 해보고 어떻게 출력되는지를 파악해보아야한다.

let st = `hello good hoho
            haha bye
            nazzoo noohoo`;
let exp3 = /[a-o]/; //퀴즈: 문자검색하는데 a - o 까지 영문자를 찾고싶어 일치하는것을
let result = st.match(exp3);
console.log(result);

console.log("-------------");

match() : 출력 (전역검색 플래그 가 없는경우)

하나의 위치는 0이고 입력값은 ~~이다.

 

3) 전역검색 플래그

let st = `hello good hoho
            haha bye
            nazzoo noohoo`;
let exp3 = /[a-o]/g;  //   /w는 모든문자,인데 [a-o] 는 하나이다.
//퀴즈: 문자검색하는데 a - o 까지 영문자를 찾고싶어 일치하는것을
let result = st.match(exp3);
console.log(result);

g를 추가적으로 붙여준다 

 

여기서 g(global)는 전역검색 플래그라고한다.

g가 없으면 최초한번 검색된것만 반환하지만, g가 있으면 모든 검색결과를 배열로 반환한다.

4) 정규식 갯수 반복패턴 (+ : 최소한개 혹은 여러개)

let html = `<div>
                <h2>hello</h2>
                <ul>
                    <li>okay</li>
                    <li>
                        <b>bye</b>
                    </li>
                </ul>
            </div>`;

// let exp3 = new RegExp("<.>", "i");
// let exp3 = /<.>/;
// let result = html.match(exp3);
// console.log(result);

let st = `hello good hoho
            haha bye
            nazzoo noohoo`;
let exp3 = /[a-o]+/g;  //   /w는 모든문자,인데 [a-o] 는 하나이다.
//퀴즈: 문자검색하는데 a - o 까지 영문자를 찾고싶어 일치하는것을
let result = st.match(exp3);
console.log(result);

알파벳 a 부터 o까지 중에 +한글자씩 반복하는데, '만족할 때 까지 그룹화' 해서 하나씩 반환한다.

이 경우 포함되면 쭉 넣어주다가 없으면 다음 인덱스 배열로 다시 넣어주는거야

 

5) 숫자까지 나오게하기

숫자가 1-5 까지 나오게 하기

 let exp3 = /[a-o1-5]+/g;

let exp3 = /[a-o]+[1-5]+/g;

이거는 하게되면 null이 나온다.

let exp3 = /[a-o]+|[1-5]+/g;

가운데 | 를 넣어주면 해결이 돼! or를 의미하는거야 위 []와 비슷한거야

[] 는 [] 안에있는것중에 or처리 묶음을 의미하는거야

 

5) 태그와 컨텐트 정규식 만들기 (크롤링용)

let st = `<hello> good</hello> hoho 3273
            haha <bye> 8216 </bye>
            nazzoo noohoo`;
// let exp3 = /<[a-o]+>|[1-5]+/g;  //   /w는 모든문자,인데 [a-o] 는 하나이다.
let exp3 = /<[a-z]+>|[\w]|<\/[a-z]+>/g;
let exp4 = /<\w+>.+<\/\w+>+/g;

. : 모든 문자를 의미한다

<\/\w+>

: <\ 문자 

: /\w 문자,숫자의미

: + 반복 의미

: > 한번 

(4) exportation

1)

import 할 때 {} 를 쓰면 디스트럭쳐럼처럼 해 그런데 받아올 때 이름이 같아야해 (디스럭처링 처럼)

이 경우 내려쓰기 방식으로도 가능해

 

default 하면 

 

import * as module from ".js" 로 하면 모든것을 * module로 가능해

 

4. promise

(1) 들어가며

1) 기존 콜백함수의 필요성과 문제점

비동기는 callback 함수를 이용이 가능해

let url = "http://www.";
    function download(url ,callback){
        //이 함수는 우리가 만든 함수가 아니라고 가정하자.
        // 다운로드 완료
        //오랜시간이 흐른뒤에!!
        callback([2,4,3]);
    }


    // ---------------------
    // 여기는 download 라이브러리를 사용하는 내 코드
    // let result = download(); //오랜시간을 잡아먹는 코드
    // console.log(result); //먹통 언제옴?

    // 내가 그랬지 오래걸린다고! 그러니까 이따 완료되면 알려줄거니까
    function downloadHandler(result){
        console.log(result); //데이터가 왔음
    }
    
    //미리 함수를 만들어서 나중에 이 함수를 호출해서 다운로드 완료를 알려달라고 함
    /* let result = */ download(url, downloadHandler);

    //그런데 일반적으로 함수를 미리 만들지않고 넘겨주면서 정의한다
    download(url ,function(result){
        console.log(result);
    })

과거 콜백함수는 데이터를 웹에서 받을 때, 데이터를 받을 때 많은시간이 걸렸다. 

     여기는 download 라이브러리를 사용하는 내 코드
     let result = download(); //오랜시간을 잡아먹는 코드
     console.log(result); //먹통 언제옴?

이 부분에 있어서 result에는 데이터가 들어오기전에 동기적으로 지속적으로 대기를 하였다.

 

그래서 콜백이 대두하였다.

두가지 방식이 있다. 함수를 미리 만들어서 호출하거나, 미리만들지 않고 넘겨주면서 정의하는 방식이다.

//<방법 1>    
// 내가 그랬지 오래걸린다고! 그러니까 이따 완료되면 알려줄거니까
    function downloadHandler(result){
        console.log(result); //데이터가 왔음
    }
    
    //미리 함수를 만들어서 나중에 이 함수를 호출해서 다운로드 완료를 알려달라고 함
    /* let result = */ download(url, downloadHandler);



//<방법 2>    -> 중첩발생
    //그런데 일반적으로 함수를 미리 만들지않고 넘겨주면서 정의한다
    download(url ,function(result){
        console.log(result);
    })

그런데 콜백함수는 문제가 있어

첫번째 가독성이 좋지않다

두번째 에러발생시 처리가 곤란하고, 다수의 비동기 처리도 한계가 있다.

 

이러한 연유로 promise가 등장했고, 비동기 처리시점을 명확하게 표현 할 수있다.

 

2) promise 의 대두

 위의 방식이 다음처럼 바뀌는 것을바란다. 
 1. 서비스 함수가 인자로 직접 콜백(위 방법1)을 받지않고, 콜백을 받는 도구를 따로 두지않음

2. 콜백을 직접 받지 않음으로써 중첩(방법2) 줄이자 이런것들을 위한 도구가 Promise객체인거임 

 //위의 방식이 다음처럼 바뀌는 것을바란다.
    //1. 서비스 함수가 인자로 직접 콜백을 받지않고,
        // 콜백을 받는 도구를 따로 두지않음
    //2. 콜백을 직접 받지 않음으로써 중첩을 줄이자
        // 이런것들을 위한 도구가 Promise객체인거임

    console.log("---promise---");
    
    //실제로 이부분은 남이 만드는거야 우리가 쓰는건 아래 promise를 해!
    function downloadPromise(url){
        //이 함수는 우리가 만든 함수가 아니라고 가정하자.
        // 다운로드 완료
        //오랜시간이 흐른뒤에!!
        return new Promise(function(resolve){
            resolve([2,4,3]);
        })
    }

    //콜백을 promise로 받겠다 => '처리'와 '호출'을 나누겠다

    let promise = downloadPromise(url);
    
    promise
    .then(function(result){
        return result[0]; //데이터가 왔다!!!
    })
    .then(function(n){
        console.log(n);
    });
    

    console.log("---promise---");
    console.log("-------------");

}

Promise()함수는 reslovereject함수를 인자로 가진다

여기서 reslove는 비동기처리가 성공했을 때 호출되는 함수이고

reject는 비동치 처리가 실패했을 때 호출되는 함수이다.

 

상단 new Promisereslove함수는 비동기처리가 성공될 때 [2,4,3] 을 반환하게끔 하는 함수이다.

 

그 이후 promise에서는 downladPromise()에서 호출을 하고나서, reslove로 배열[2,3,4]를 받는다.

받으면 then 으로 reslove, reject를 받는데, 둘중에서 성공한 상태이기 때문에 reslove를 받는다.

 

받고나면 then 메소드promise 를 반환한다. 그리고 이 promise는 다음 then에다가 reslove 등을 다시 호출된다.

뒤늦게 63번줄의 2가 출력된 모습

 


1. 보충

 

2. 회고 

1) 어제 궁금했던 symbol()이 인터페이스와 같이 설계도를 가질 수있게끔하는것이 신기한것같다

 

2) 그리고 이터레이션에 대해서 만드는게 제너레이터인데 * 하나로 끝나는것이 흥미롭다

 

3) 드디어 promise()를 어느정도 이해할 수 있게 되어서 다행이다 보면볼수록 익숙해지고 내것이 되는것같다

'배움 __IL > TIL 1기' 카테고리의 다른 글

TIL : 95번째- 230421 [4-3-금]  (0) 2023.04.21
TIL : 94번째- 230420 [4-3-목]  (0) 2023.04.20
TIL : 92번째- 230418 [4-3-화]  (0) 2023.04.18
TIL : 91번째- 230417 [4-3-월]  (0) 2023.04.17
TIL : 88번째- 230411 [4-2-화]  (0) 2023.04.11