728x90

사용자 정의 이터러블을 구현하며 이터러블에 대해 정확하게 알아봅니다.

    /**
     * 사용자 이터러블 정의
     */
    const iterable = {
        [Symbol.iterator]() {
            let i = 1;
            return {
                next() {
                    return i > 3 ? {done: true} : {value: i++, done: false};
                }
            };
        }
    };
    
    let iterator = iterable[Symbol.iterator]();
    
    // console.log(iterator.next());
    
    for (const a of iterable) {
        console.log(a);
    }

위와 같은 사용자가 직접 정의한 이터러블을 본다면, iterable에 [Symbol.iterator]()가 구현되어있으므로, for ... of 문법을 통하여 리스트 반복이 가능합니다.

실제 실행시 기본 내장 객체인 array, map, set과 마찬가지로 next() 함수가 리턴되며 반환됩니다. for ... of문 내부적으로는 iterator.next()를 실행하면서 클로저인 next 가 i를 하나씩 증가시키며 a에 i값을 하나씩 담게 되면서 모든값을 반복하여 출력 하게 됩니다.

 

이전 포스트인 이터러블/이터레이터에서 말씀 드렸던 것처럼, 이터러블은 [Symbol.iterator]() 값 자체에도 본인을 리턴하는 [Symbol.iterator]() 가 있으며, iterator.next(); 와 같이 일부분을 선행하여 진행하였을 경우, 그 이후의 값을 부터 반복이 이루어질 수가 있습니다.

 

하지만 위의 사용자 정의 iterable 의 경우 자신의 [Symbole.iterator]() 값을 가지고 있는 iterator 는 for ... of 문으로 반복할 수 없으며, iterator.next()를 선행한 후에도 처음 값부터 for ... of 문으로 반복이 이루어 집니다.

 

내장 객체와 동일한 이터러블/이터레이터 프로토콜을 지원하기 위해서 자신의 자신의 [Symbole.iterator]()에서 자기 자신을 리턴하는 자신의 [Symbole.iterator]()를 만들어 줍니다.

    /**
     * 사용자 이터러블 정의
     */
    const iterable = {
        [Symbol.iterator]() {
            let i = 1;
            return {
                next() {
                    return i > 3 ? {done: true} : {value: i++, done: false};
                },
                [Symbol.iterator]() {
                    return this;
                }
            };
        }
    };
    let iterator = iterable[Symbol.iterator]();
    iterator.next();
    for (const a of iterable) {
        console.log(a);
    }
    
    // > 2
    // > 3

위와 같이 [Symbole.iterator]()값에 자기자신을 리턴하는 [Symbole.iterator]() 객체를 만들어준다면, [Symbole.iterator]() 자체로도 for ... of 문으로 반복이 가능하며, iterator.next(); 로 선행 후에는 다음값부터 for ... of 문으로 반복이 됩니다.

이처럼 이터러블/이터레이터 프로토콜은 ES6에서 지원하는 내장 값만 해당 프로토콜을 지원하는것이 아니라, 오픈 소스 또는 브라우저의 dom과 같은 값들이 반복 및 순회가 가능한 형태의 값을 가진 값들은 대부분 이터러블/이터레이터 프로토콜을 따라 구현이 되고 있습니다.

아래 예제를 통해 관련 코드 확인이 가능합니다.

Example

/**
 * dom NodeList 이터러블 정의
 */
const list = document.querySelectorAll('*');
for (const a of list) {
    console.log(a);
}

const queryAllIterator = list[Symbol.iterator]();
queryAllIterator.next();
queryAllIterator.next();
for (const a of queryAllIterator) {
    console.log(a);

위와 같이 document.querySelectorAll 도 for ... of 문으로 반복순회가 가능하며, 이는 해당 객체가 배열이라서가 아닌 [Symbol.iterator]() 가 구현이 되어 있기 때문에 반복 순회가 가능한 것입니다. 이터러블/이터레이터 프로토콜 특성에 따라 next() 를 이용한 우선 순회 및 자기자신에 대한 [Symbole.iterator]() 리턴 특성 또한 모두 포함하고 있습니다.

 

 출처: 프로그래머스 - 강사 유인동/함수형 프로그래밍과 ES6

728x90

+ Recent posts