티스토리 뷰
ES6에서 생겨난 개념.
iterator와 generator.
generator는 iterator에 의존하는 개념이기 때문에 iterator부터 시작하자.
iterator의 'iterate'는 '순회하다.'라는 뜻이다.
뜻에서 짐작할 수 있듯이 배열이나 객체의 값을 순회하는 역할이다.
어떻게 순회하는지 확인해보자.
iterable의 대표적인 예인 배열부터 보면
const book = [
"hi",
"i'm",
"a developer"
];
iterator는 values() 메서드를 써서 이터레이터를 만들 수 있다.
const it = book.values();
next() 메서드를 써서 순회를 진행할 수 있다.
console.log(it.next()); // { value: 'hi', done: false }
console.log(it.next()); // { value: "i'm", done: false }
console.log(it.next()); // { value: 'a developer', done: false }
console.log(it.next()); // { value: undefined, done: true }
done이 true가 되면 순회가 끝난 것이다.
for... of 구문에서 인덱스가 없이 순회할 수 있는 이유도 바로 이 iterator 때문이다.
for(let n of book){
console.log(n);
}
// hi
// i'm
// a developer
for(let n of book.values()){
console.log(n);
}
// hi
// i'm
// a developer
iterator는 독립적이다.
const it = book.values();
const it2 = book.values();
console.log(it.next()); // { value: 'hi', done: false }
console.log(it2.next()); // { value: 'hi', done: false }
이터레이터 프로토콜(iterator protocol)은 모든 객체를 iterable하게 바꿀 수 있다.
이터레이터 프로토콜을 사용하는 법은 클래스에 심벌 메서드 Symbol.iterator가 있고,
이 메서드가 이터레이터처럼 동작하는 객체, 즉 value와 done프로퍼티가 있는 객체를 반환한다면
그 클래스의 인스턴스는 iterable 하다고 할 수 있다.
class Log {
constructor() {
this.messages = [];
}
add(message) {
this.messages.push({ message, timestamp: Date.now() });
}
[Symbol.iterator](){
return this.messages.values();
}
}
이 클래스는 Symbol.iterator를 가지고 있고 이 메서드는 iterator를 반환하므로 iterable 하다.
const log = new Log();
log.add("hi");
log.add("i'm");
log.add("a developer");
for(let v of log){
console.log(v);
}
// { message: 'hi', timestamp: 1583050171741 }
// { message: "i'm", timestamp: 1583050171741 }
// { message: 'a developer', timestamp: 1583050171741 }
iterator를 직접 구현할 수도 있다.
class Log {
constructor() {
this.messages = [];
}
add(message) {
this.messages.push({ message, timestamp: Date.now() });
}
[Symbol.iterator]() {
let i = 0;
const messages = this.messages;
return {
next() {
if (i < messages.length) {
return { value: messages[i++], done: false };
}
return { value: undefined, done: true };
}
};
}
}
iterator의 순회 그리고 done을 true로만 만들면 무한한 특성을 이용해 간단하게 피보나치수열을 구해보면
class FibonacciSequence {
[Symbol.iterator]() {
let a = 0,
b = 1;
return {
next() {
let value = b;
b +=a;
a = value;
return {value, done:false};
}
};
}
}
const fib = new FibonacciSequence();
let i = 0;
for (let v of fib) {
if (i++ > 9) break;
console.log(v);
}
generator
generator는 iterator를 사용해 자신의 실행을 제어하는 함수다.
일반적인 함수의 경우에는 호출을 한 경우 호출자는 함수의 실행에 대해서 제어권이 없어서 함수가 종료될 때까지 기다리는 수밖에 없다.
generator는 다음과 같은 두 가지 새로운 개념을 도입했다.
1. 함수의 실행을 개별적 단계로 나눔으로써 함수의 실행을 제어한다는 것.
2. 함수와 통신이 가능하다는 것.
제너레이터를 만들 때는 뒤에 *를 붙인다.
제너레이터에서는 return키워드 외에도 yield를 쓸 수 있다.
function* rainbow(){
yield 'red';
yield 'orange';
yield 'yellow';
yield 'green';
yield 'blue';
yield 'indigo';
yield 'violet';
}
yield 키워드를 호출자에게 제어권을 양도(yield) 할 수 있다.
const it = rainbow();
console.log(it.next()); // { value: 'red', done: false }
console.log(it.next()); // { value: 'orange', done: false }
for... of에서도 사용 가능하다.
const it = rainbow();
for(let v of it){
console.log(v);
}
이제 이 yield에 대해서 알아보자.
function* communicate() {
const name = yield "What is your name?";
const color = yield "What is your favorite color?";
return `${name}'s favorite color is ${color}`;
}
const it = communicate();
console.log(it.next()); // { value: 'What is your name?', done: false }
console.log(it.next('Jack')); // { value: 'What is your favorite color?', done: false }
console.log(it.next('orange')); // { value: "Jack's favorite color is orange", done: true }
it.next()를 통해서 제어권을 넘겨준다(yield). 넘겨줄 때 iterator에서 쓰이는 value값을 넣어줄 수 있다.
그 다음행에 it.next('Jack')을 통해서 다시 호출하면 yield 'What is your name?' 이 전체가 'Jack'이 된다.
다시 제너레이터는 제어권을 호출자에게 넘겨주고 yield 'What is your favorie color?' 전체가 'orange'가 된다. 그리고 마지막에 return을 함으로써 제너레이터 실행이 종료된다.
generator에서는 마지막이 {value: undefined, done: true}가 아니다.
const it = communicate();
for(let v of it){
console.log(v);
}
// What is your name?
// What is your favorite color?
for... of 루프에서는 return값을 출력할 수 없다.
generator에서 되도록이면 return값에 중요한 값을 입력하지 않아야 한다.
참고문헌: Learning Javascript - 이선 브라운
'Javascript' 카테고리의 다른 글
다형성과 다중 상속 (0) | 2020.03.01 |
---|---|
객체프로퍼티 나열 (0) | 2020.03.01 |
Map과 Set (0) | 2020.03.01 |
- Total
- Today
- Yesterday
- Iterator
- 다형성
- 다중상속
- 자료구조
- express-session
- 맵
- pm2 #cluster #Javascript
- virtuals
- saveUnitialized
- mongoose
- resave
- 이중 연결리스트
- 선형리스트
- index
- instance method
- alias
- query helper
- 자료구조 #딕셔너리 #해시
- set
- javascript
- mixin
- Node.js
- 집합
- static method
- Generator
- MongoDB
- map
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |