💻 프로그래밍

Iterator

이터레이터

컬렉션 요소를 순회하는 객체. for 루프의 기반.

📖 상세 설명

Iterator(이터레이터)는 컬렉션의 요소들을 하나씩 순차적으로 접근할 수 있게 해주는 객체입니다. 배열, Set, Map 등 다양한 자료구조의 내부 구현을 몰라도 일관된 방식으로 요소를 순회할 수 있게 해주며, 이를 통해 데이터 구조와 알고리즘을 분리하는 디자인 패턴의 핵심이 됩니다.

JavaScript에서 이터레이터는 `next()` 메서드를 가진 객체로, 호출할 때마다 `{ value, done }` 형태의 결과를 반환합니다. value는 현재 요소의 값이고, done은 순회가 끝났는지를 나타내는 불리언 값입니다. 이 프로토콜을 따르는 객체는 `for...of` 루프에서 자동으로 사용될 수 있습니다.

Python에서는 `__iter__()`와 `__next__()` 매직 메서드로 이터레이터를 구현합니다. Java에서는 `Iterator` 인터페이스의 `hasNext()`와 `next()` 메서드를 사용합니다. 언어마다 문법은 다르지만 "현재 요소 반환 + 다음으로 이동"이라는 핵심 개념은 동일합니다.

실무에서 이터레이터는 대용량 데이터 처리, 지연 평가(Lazy Evaluation), 무한 시퀀스 생성 등에 활용됩니다. 제너레이터(Generator)와 함께 사용하면 메모리 효율적인 데이터 파이프라인을 구축할 수 있어, 스트림 처리나 페이지네이션 구현에 특히 유용합니다.

💻 코드 예제

// 1. 기본 이터레이터 사용법
const numbers = [10, 20, 30];
const iterator = numbers[Symbol.iterator]();

console.log(iterator.next()); // { value: 10, done: false }
console.log(iterator.next()); // { value: 20, done: false }
console.log(iterator.next()); // { value: 30, done: false }
console.log(iterator.next()); // { value: undefined, done: true }

// 2. for...of 루프 (내부적으로 이터레이터 사용)
const fruits = ['사과', '바나나', '딸기'];
for (const fruit of fruits) {
    console.log(fruit); // 사과, 바나나, 딸기 순서대로 출력
}

// 3. 커스텀 이터레이터 구현 - Range 객체
class Range {
    constructor(start, end, step = 1) {
        this.start = start;
        this.end = end;
        this.step = step;
    }

    [Symbol.iterator]() {
        let current = this.start;
        const end = this.end;
        const step = this.step;

        return {
            next() {
                if (current <= end) {
                    const value = current;
                    current += step;
                    return { value, done: false };
                }
                return { value: undefined, done: true };
            }
        };
    }
}

// 사용 예시
const range = new Range(1, 5);
console.log([...range]); // [1, 2, 3, 4, 5]

for (const num of new Range(0, 10, 2)) {
    console.log(num); // 0, 2, 4, 6, 8, 10
}

// 4. 제너레이터로 이터레이터 쉽게 만들기
function* fibonacci(limit) {
    let [prev, curr] = [0, 1];
    while (curr <= limit) {
        yield curr;
        [prev, curr] = [curr, prev + curr];
    }
}

console.log([...fibonacci(100)]);
// [1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]

// 5. Map과 Set의 이터레이터
const userMap = new Map([
    ['alice', { age: 25 }],
    ['bob', { age: 30 }]
]);

for (const [name, info] of userMap) {
    console.log(`${name}: ${info.age}세`);
}

🗣️ 실무에서 이렇게 말하세요

💬 회의에서
"대용량 CSV 파일을 처리할 때 전체를 메모리에 올리면 OOM이 발생합니다. 이터레이터 패턴으로 한 줄씩 읽어서 처리하면 메모리 사용량을 일정하게 유지할 수 있어요."
💬 면접에서
"JavaScript의 이터러블 프로토콜은 Symbol.iterator 메서드를 구현하면 됩니다. 이 메서드가 next()를 가진 이터레이터 객체를 반환하면, for...of나 스프레드 연산자에서 자동으로 순회가 가능합니다."
💬 코드 리뷰에서
"여기 for...in 대신 for...of를 사용하세요. for...in은 객체의 열거 가능한 속성을 순회하고, for...of는 이터러블의 값을 순회합니다. 배열에 for...in을 쓰면 인덱스가 문자열로 나와서 버그가 생길 수 있어요."

⚠️ 흔한 실수 & 주의사항

이터레이터는 일회용

이터레이터는 한 번 순회하면 재사용할 수 없습니다. 다시 순회하려면 새 이터레이터를 생성해야 합니다. `[...iterator]`로 소진된 이터레이터를 다시 펼치면 빈 배열이 됩니다.

for...in vs for...of 혼동

`for...in`은 객체의 키(속성명)를 순회하고, `for...of`는 이터러블의 값을 순회합니다. 배열에 `for...in`을 사용하면 인덱스가 문자열로 반환되어 의도치 않은 버그가 발생할 수 있습니다.

제너레이터로 간단하게 구현

커스텀 이터레이터를 직접 구현하는 것보다 제너레이터 함수(function*)를 사용하면 yield 키워드로 훨씬 간결하게 이터레이터를 만들 수 있습니다. 상태 관리도 자동으로 처리됩니다.

🔗 관련 용어

📚 더 배우기