개인노트-인강

개인노트 nomad ES6의 정석 #12 Generators and Maps

roroism 2023. 2. 26. 16:13

# 12.0 Generators

Generator는 iterable한 객체를 반환합니다. iterable 하다는 뜻은 배열의 보다 일반적인 의미로, Array type을 포함하여 string, nodeList 등 유사 배열 객체 등을 포함하며, for ...of 문법을 사용할 수 있다는 특징이 있습니다.

 

Generators는 기본적으로 pause할 수 있는 함수입니다.

Generators를 사용하기 위해서는 몇가지 규칙을 따라야합니다.

1. function*를 사용합니다.

function에 *를 사용하게 되면 한 단어를 해제하게 됩니다. 그 단어는 yield입니다.

2. yield

yield는 Generators에서 return처럼 쓰입니다.

 

// Generator function
function* listPeople() {
    yield "Dal";
    yield "Flynn";
    yield "Mark";
    yield "Godkimchi";
    yield "Japan Guy";
}

// Generator function 호출
const listG = listPeople(); // 아무런 일도 일어나지 않습니다.

console.log(listG);

console.log(listG) 출력결과

console.log(listG)를 보면 object가 {<suspended>} 입니다.

 

그리고 list.next()를 실행하면..

listG.next()
// 출력
// {value: "Dal", done: false}

첫번째 value 인 Dal이 출력됨을 확인할 수 있습니다. value만 return하는 것이 아니라 done:false 를 리턴합니다. 이는 generator가 끝나지 않았음을 의미합니다.

 

계속 .next()를 실행하면..

listG.next()
// 출력
// {value: "Dal", done: false}
listG.next()
// 출력
// {value: "Flynn", done: false}
listG.next()
// 출력
// {value: "Mark", done: false}
listG.next()
// 출력
// {value: "Godkimchi", done: false}
listG.next()
// 출력
// {value: "Japan Guy", done: false}

listG.next()
// 출력
// {value: undefined, done: true}
// 이후에 계속 listG.next()를 실행해도 
// 같은 결과 {value: undefined, done: true} 를 출력합니다.

 

## 사용 예

const friends = ["Dal", "Flynn", "Mark", "Godkimchi", "Japan Guy"];

function* friendTeller() {
    for(const friend of friends) {
        yield friend;
    }
}

const friendLooper = friendTeller();
friendLooper.next();
{value: "Dal", done: false}
friendLooper.next();
{value: "Flynn", done: false}
friendLooper.next();
{value: "Mark", done: false}
friendLooper.next();
{value: "Godkimchi", done: false}
friendLooper.next();
{value: "Japan Guy", done: false}
friendLooper.next();
{value: undefined, done: true}

yield로 실행을 중지 할 수 있고, next를 호출하여 실행할 수 있습니다.

 

# 12.1 Proxies

Proxy 객체를 사용하면 한 객체에 대한 기본 작업을 가로채고 재정의하는 프록시를 만들 수 있습니다.

https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Proxy

 

proxy를 filter처럼 생각해볼 수 있습니다.

const userObj = {
    username: "nico",
    age: 12,
    password: 1234
}

const userFilter = {};

// userFilter를 통해서 userObj를 filter할 수 있습니다.
const filteredUser = new Proxy(userObj, userFilter);

proxy는 두 개의 input을 가지고 있습니다.

하나는 target (filter를 하고 싶은 object),

다른 하나는 handler (target의 필터)

 

filteredUser.age // 출력 : 12
filteredUser.password // 출력 : 1234

위처럼 filteredUser에서 userObj의 값을 가져올 수 있습니다. 참고로 userFilter는 현재 빈 객체 입니다.

 

기본적으로 filteredUser를 호출하면 userFilter가 호출되고 그 다음에 userObject의 value가 반환되거나 반환되지 않을 수 있습니다.

 

const userObj = {
    username: "nico",
    age: 12,
    password: 1234
}

const userFilter = {
    get: () => {
        console.log("Somebody is getting something");
        // return "NOTHING"; // return도 가능.
    }
    set: () => {
        console.log("Somebody wrote something");
    }
};

// userFilter를 통해서 userObj를 filter할 수 있습니다.
const filteredUser = new Proxy(userObj, userFilter);

filteredUser.password // Somebody is getting something
filteredUser.active = true // Somebody wrote something

위에서 get, set 함수이름은 임의로 정한 것이 아닌 정해놓은 함수입니다. (proxy 문서 참고)

filter 객체 안의 get, set 등과 같은 함수들을 trap이라고 부릅니다.

 

filteredUser.password 를 실행하면 proxy는 trap을 호출하고, get이 실행됩니다.

filteredUser.active 라는 property를 새로 만들고 true를 할당하면,(filteredUser.active = true) set이 실행됩니다.

 

그리고 filteredUser를 출력해보면..

새로 만든 active 속성이 보이지 않습니다.

 

정리하면..

1. Proxy를 만들고 Proxy에게 targetObj와 userFilter를 인수로 입력합니다.

2. userFilter는 몇 가지 properties를 가집니다. (get 이나 set 등) 

3. Proxy는 userObj의 이벤트를 가로채서 그 이벤트의 행위를 못하게 하고, trap으로 정의한 것을 실행합니다.

 

## trap들의 argument

const userObj = {
    username: "nico",
    age: 12,
    password: 1234
}

const userFilter = {
    get: (target, prop, receiver) => {
        console.log(target); // userObj // object출력 여기서는 userObj
        console.log(prop); // age // 속성이름출력 여기서는 호출한 age
        console.log(receiver); // proxy를 출력합니다.
    }
    set: () => {
        console.log("Somebody wrote something");
    }
};

const filteredUser = new Proxy(userObj, userFilter);

filteredUser.age;

trap에는 3개의 argument를 사용할 수 있습니다. 첫번째는 target, 두번째는 prop, 세번째는 receiver.

 

1. target argument

출력 결과

console.log(target)

실제 object가 출력됩니다.

 

2. prop argument

출력 결과

 

console.log(prop)

user가 요청한 property data(속성 이름)을 logging합니다.

 

3. receiver argument

출력 결과

console.log(receiver)

proxy를 출력합니다.

 

### argument 사용

1. 사용 예1

const userFilter = {
    get: (target, prop, receiver) => {
        return target[prop];
    }
};

const filteredUser = new Proxy(userObj, userFilter);

filteredUser.age; // 12

만약에 누군가 age를 호출한다면 target[prop] 으로 age를 반환하게 할 수 있습니다.

 

2. 사용 예2

const userFilter = {
    get: (target, prop, receiver) => {
        return prop === "password" ? `${"*".repeat(5)}` : target[prop];
    }
};

const filteredUser = new Proxy(userObj, userFilter);

filteredUser.age; // 12

 

# 12.2 Should you learn proxies or generators?

proxies 와 generators를 배워야 할까요?

노마드코더 생각으로는 그렇게 생각하지 않습니다. 하지만 라이브러리를 만드는 사람에게는 유용합니다.