[JavaScript] 이터레이터(Iterator),이터러블(Iterable)

이터러블(Iterable, 순회 가능한 자료구조)

이터러블은 Symbol.iterator 메소드를 구현하거나 프로토타입 체인에 의해 상속한 객체를 말한다.

Symbol.iterator 메소드는 이터레이터를 반환한다.

이터러블은 for…of 문으로 순회할 수 있으며 이외에도 spread 문법, 디스트럭쳐링 할당, Map과 Set의 생성자에도 사용된다.

단순하게 '자료구조를 반복할 수 있게 하는 객체' 정도로 이해해 본다.

Array, String, Map, Set, DOM이 이터러블이고, 이런 것을 반복할 수 있게 하는 것이 이터레이터다.


이터레이터(Iterator, 반복자)

이터러블/이터레이터 프로토콜은 next 메소드를 사용하여 이터러블을 순회하며 value, done 프로퍼티를 갖는 이터레이터 객체를 반환한다. 이 규약을 준수한 객체가 이터레이터이다.

이터러블/이터레이터 프로토콜을 준수한 이터러블은 Symbol.iterator 메소드를 소유한다. 이 메소드를 호출하면 이터레이터를 반환한다.

반환된 이터레이터를 next 메소드를 사용하여 호출하면 이터러블을 순차적으로 한 단계씩 순회하며 value, done 프로퍼티를 갖는 객체를 반환한다.

순회하는동안 value값과 done: false를 반환하다가 순회가 완료되면 value: undefined, done: true를 반환한다. 여기서 done 프로퍼티는 이터러블의 순회 완료 여부를 반환하는것이다.


과정
iterable[Symbol.iterator]() ---> iterator ---> iterator.next() ---> return { value, done }

이터러블(iterable, 순회 가능한 자료구조)은 Array, String, Map, Set, DOM구조이며, [Symbol.iterator]() 메서드를 사용하여 iterator를 생성하고 next() 메서드로 값을 하나씩 순회할 수 있다.


[Symbol.iterator]()를 통해 생성된 이터레이터에 [Symbol.iterator]()를 다시 해줄경우
자기자신을 가르키기 때문에 진행된 값들을 초기화를시켜 처음부터 다시 반복할수있게해준다.


### 이터러블/이터레이터 프로토콜
- 이터러블: 이터레이터를 리턴하는 [Symbol.iterator]() 를 가진 값
- 이터레이터: { value, done } 객체를 리턴하는 next() 를 가진 값
- 이터러블/이터레이터 프로토콜: 이터러블을 for...of, 전개 연산자 등과 함께 동작하도록한 규약


이터러블, 이터레이터 예시

// example1
const arr = [1, 2, 3];
let iterator = arr[Symbol.iterator]();
console.log(iterator); //Object [Array Iterator] {} 이터레이터를 반환한다.

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

console.log(iterator[Symbol.iterator]() === iterator); //true


// example2
const arr = [1, 2, 3, 4, 5];

let iterator = arr[Symbol.iterator]();
console.log(iterator); //Object [Array Iterator] {} 이터레이터를 반환한다.

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

console.log(iterator[Symbol.iterator]() === iterator); //true

for (const num of iterator) {
console.log(num); //4 , 5
}


위의 코드는  이터러블 객체인 arr을 [Symbol.iterator](); 메서드를 사용해서 이터레이터 객체를 iterator변수에 담았고 이터레이터를 next() 메서드를 사용하여 값을 순회하고 있다. next()메서드를 사용하여 일부를 진행하다가 순회도 가능하다.

잘 구현된 이터러블은 이터레이터를 만들었을 때 이터레이터를 진행하다가 순회할수도 있고 또 이터레이터를 for... of 문에 넣었을 때 나머지 모든 값들을 순회할 수 있도록 되어있는 것이다.

iterator역시 [Symbol.iterator]()를 가지고 있다. 그리고 이터레이터에 [Symbol.iterator]()를 실행한 값은 자기 자신이다. 

이렇게 이터레이터가 자기자신을 반환하는 [Symbol.iterator]()를 가지고 있을때 잘 만들어진 이터레이터/이터러블 이라고할 수 있다.


++
브라우저에서 사용되는 DOM과 관련된 값들이라던지 여러가지 값들도 이터러블,이터레이터 프로토콜을 따르고 있다.
nodelist의 경우 배열이 아니지만 순회가 가능한데 그 이유는 [Symbol.iterator]()가 구현되어 있기 때문이다.

댓글