Generator
Generator란
Generator(이하, 제너레이터) 함수는 일반 함수와 다르게 여러 개의 값을 하나씩 반환할 수 있는 함수다. 때문에 제너레이터 함수는 function* 으로 선언하고 return 뿐만 아니라 yield 키워드로 값을 반환하는 특별한 문법 구조를 가진다. 이때 return을 주의해야 하는데, return으로 반환된 값은 for ...of 나 스프레드 문법 등에서 처리할 수 없다는 점을 기억해야한다.
function* generateSequence() {
yield 1;
yield 2;
return 3;
}
let generator = generateSequence();
for(let value of generator) {
alert(value); // 1, 2가 출력됨
}
앞서 제너레이터 함수는 여러 개의 값을 하나씩 반환한다고 설명했다. 이를 가능하게 하는 역할이 바로 제너레이터 함수를 호출하면 반환받는 제너레이터 객체이다.
제너레이터 객체는 next() 메서드를 가지고 있는데 이 메서드를 호출하면 { value, done } 형태의 객체를 반환받게 된다. 이 부분을 알게된다면 제너레이터는 Iterable(이하, 이터러블)임을 짐작할 수 있는데 이 부분은 우연이 아니라 제너레이터는 이터레이터를 쉽게 구현할 수 있도록 추가된 것으로 기존 이터러블 구현을 쉽게 구현할 수 있게 된다.
let range = {
from: 1,
to: 5,
*[Symbol.iterator]() { // [Symbol.iterator]: function*()를 짧게 줄임
for(let value = this.from; value <= this.to; value++) {
yield value;
}
}
};
alert( [...range] ); // 1, 2, 3, 4, 5
Generator composition
하나의 함수가 모든 일을 하는 것은 좋은 함수가 아니기 때문에 제너레이터 함수도 같은 맥락이 적용된다. 하지만 제너레이터 함수는 일반 함수와 동작 구조가 다르기 때문에 제너레이터 함수 안에 제너레이터를 Embedding할 수 있게 해주는 Generator composition(이하, 제너레이터 컴포지션) 이라는 특별한 기능을 가진다. 제너레이터 컴포지션은 끼워 넣을 다른 제너레이터 호출문 앞에 yield* 를 붙인 것으로 사용이 가능하다.
function* generateSequence(start, end) {
for (let i = start; i <= end; i++) yield i;
}
function* generatePasswordCodes() {
// 0..9
yield* generateSequence(48, 57);
// A..Z
yield* generateSequence(65, 90);
// a..z
yield* generateSequence(97, 122);
}
let str = '';
for(let code of generatePasswordCodes()) {
str += String.fromCharCode(code);
}
alert(str); // 0..9A..Za..z
이를 통해 제너레이터 함수의 재사용성과 책임 분리를 통해 좋은 코드를 작성할 수 있다.
정보 교환하기
제너레이터의 특별한 기능 또 하나는 제너레이터 함수 caller와 callee의 양방향 정보 교환이 가능하다는 것이다. 제너레이터 객체의 주요 메서드인 next()는 매개변수로 value를 받는데 이것을 통해 동작하고 있는 함수의 내부에 외부에서 값을 넣어줄 수 있다.
function* gen() {
while(true) {
var value = yield null;
console.log(value);
}
}
var g = gen();
g.next(1);
// "{ value: null, done: false }"
g.next(2);
// "{ value: null, done: false }"
// 2
여기서도 중요한 점이 있는데 next로 넘겨줄 데이터가 어느 위치에 있는지와 실행 순서를 알고 있어야 원하는 결과를 얻을 수 있다.
참고자료
https://ko.javascript.info/generators
https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Generator/next
'메모' 카테고리의 다른 글
Node.js 플랫폼 (0) | 2022.02.04 |
---|---|
Type<Challenge[]> #Easy (0) | 2022.02.04 |
Typescript로 구현한 Linked list (0) | 2022.02.01 |
JS의 메모리관리 (0) | 2022.01.13 |
Iteration protocol (0) | 2021.12.31 |