본문 바로가기
프로그래밍 언어/Javascript

자바스크립트 iterator, generator

by pagehit 2021. 8. 16.
반응형

반복가능한 객체(iterable object)와 반복자(iterator)는 ES6에서 도입되었다. 대표적으로 배열, 문자열, Set, Map은 iterable하다.

let sum = 0;
for(let i of [1,2,3]) { // Loop once for each of these values
    sum += i;
}
sum   // => 6

 

iterator 동작 방식

for/of와 spread 연산자(...)는 iterable object와 동작한다.

 

iterable object는 iterator를 반환하는 매소드를 가진 객체이다.

iterator는 iteration result object를 반환하는 next() 매소드를 가진 객체이다.

iteration result object는 프로퍼티로 value와 done을 가지는 개체이다.

iterable object를 반복시키면, iterator 매소드를 호출해 iterator 객체를 얻어 next() 매소드를 계속호출하며 done 프로퍼티가 true인지 검사한다.

let iter = [1, 2];
let iterator = iter[Symbol.iterator]();
for (let result = iterator.next(); !result.done; result = iterator.next()) {
    console.log(result.value);
}

 

iterable object 직접 구현

먼저 generator 없이 iterable object 구현해 보자.

class를 iterable하게 만드려면 Symbol.iterator를 매소드를 구현해야 한다.

class Range {
    constructor(from, to) {
        this.from = from;
        this.to = to;
    }

    has(x) {
        return typeof x === "number" && this.from <= x && x <= this.to;
    }

    [Symbol.iterator]() {
        let next = Math.ceil(this.from);
        let last = this.to;
        return {
            next() {
                return (next <= last)
                    ? {value: next++}
                    : {done: true};
            },
        };
    }
}

for (let x of new Range(1, 5)) console.log(x);

 

generator를 이용하면 iterator를 쉽게 구현할 수 있다.

 

Generator

generator 함수는 function*로 정의한다. 이 함수는 함수의 body를 실행하지 않고 iterator인 generator object를 반환한다. 이 객체의 next() 매소드가 호출되면 yield를 만날 때 까지 함수의 body가 실행된다.

function* oneDigitPrimes() { 
    yield 2;
    yield 3;
    yield 5;
    yield 7;
}

let primes = oneDigitPrimes();

primes.next().value          // => 2
primes.next().value          // => 3
primes.next().value          // => 5
primes.next().value          // => 7
primes.next().done           // => true

 

function* sequence(...iterables) {
    for(let iterable of iterables) {
        for(let item of iterable) {
            yield item;
        }
    }
}

// 위와 같음 yield*
function* sequence(...iterables) {
    for(let iterable of iterables) {
        yield* iterable;
    }
}

[...sequence("abc",oneDigitPrimes())]  // => ["a","b","c",2,3,5,7]

 

 

반응형

댓글