이터러블 (Iterable)

순회가능한 객체를 말합니다. 

순회 가능한 객체는 Symbol.iterator 심볼 속성을 가지고 있으며 이터레이터 객체를 반환하는 객체를 말합니다.

이러한 것을 이터러블 프로토콜이라고 하며 이터러블 객체라고 합니다.

 

이터레이터 (Iterator)

이터러블 메소드로 반환하는 객체입니다.

next 메소드를 구현하고 있으며 value, done을 반환하는 객체입니다.

반환되는 IteratorResult는 {done: boolean, value: any} 형태의 단순한 객체입니다.

next 메소드를 통해 모든 값을 돌고 나면 done이 true로 나오며 끝납니다.

한번 끝난 이터레이터는 다시 돌아가지 않으며 value가 undefined로 리턴합니다

이러한 것을 이터레이터 프로토콜이라고 합니다.

 

for of 루프는 순회 시작 전 [Symbol.iterator]() 메소드를 호출하여 이터레이터 객체를 얻습니다.

그 후에 순차적으로 next 메소드를 호출하며 하나씩 순회합니다.

보통 이터러블 프로토콜과 이터레이터 프로토콜을 하나의 객체에 모두 구현하는 것이 일반적입니다.

// 영원히 0을 반환하는 무한 이터레이터 예시
var zeroesForeverIterator = {
    [Symbol.iterator]: function () {
        return this;
    },
    next: function () {
        return {done: false, value: 0};
    }
};

 

사용자 이터레이터 객체 생성

이터러블 프로토콜은 obj[Symbol.iterator]: Function => Iterator로 표현할 수 있습니다.

그 후 이터레이터 프로토콜을 따라 value, done가 들어있는 오브젝트를 반환하는 next 메소드를 가진 객체를 반환하면 됩니다. 

const iterable1 = {};

iterable1[Symbol.iterator] = function* () {
  yield 1;
  yield 2;
  yield 3;
};

console.log([...iterable1]); // Array [1, 2, 3]

 

제너레이터 (Generator)  

이터러블, 이터레이터 객체를 만드는 손 쉬운 방법입니다.

동작은 function* 문법을 사용해서 작성하며 next를 통해 실행합니다.

next 메소드를 통해 실행이 되며 yield 문을 만나면 정지합니다. 

next 메소드를 호출함으로써 값을 소비할 수 있습니다. 

function* 문법을 통해 함수가 생성되고 최초로 호출될때 함수 내부의 어떠한 코드도 실행되지 않습니다.

이때 생성자 함수가 반환되는데 이것을 제너레이터 함수라합니다. 그 후 값을 소비하며 함수로 부터 반환되는 객체를 제너레이터라고 합니다.

 

즉, 제너레이터 객체는 이터레이터 객체입니다. 

(이터레이터 프로토콜을 따르고 있습니다.)

 

예시

값이 더이상 업을 경우 value: undefined, done: true가 반환된 것이 확인됩니다.

function* generatorFunc() {
  yield 1;
  yield 2;
  yield 3;
}

const it = generatorFunc();

console.log(it.next()); // { value: 1, done: false }
console.log(it.next()); // { value: 2, done: false }
console.log(it.next()); // { value: 3, done: false }
console.log(it.next()); // { value: undefined, done: true }

 

제너레이터 적극 활용한 예로 redux-saga가 있습니다.

 

 

 

 


 

참고 및 정의 출처

+ Recent posts