let iter = (1..)
.filter(|x| x % 2 == 0)
.take(5); // 여기선 아직 실행되지 않음
위 코드는 Rust Iterator 예제이다. Iterator 연산은 기본적으로 지연 평가(Lazy Evaluation)의 대상이다. collect(), sum()과 같은 consumer가 호출되기 전까지 실제로 실행되지 않는다.
Iterator - JavaScript | MDN
자바스크립트에서는 이와 같은 기능들이 ES17(ECMAScript 2026)에서 추가되었다.
새로운 기능을 확인하기 이전에 이터러블과 이터레이터에 대한 정의를 확인할 필요가 있다.
📦 이터러블 (Iterable)
• for...of 루프나 전개 연산자(...)에 사용할 수 있는 객체
• 필수 조건: Symbol.iterator 메서드가 있어야 함
🔁 이터레이터 (Iterator)
• .next() 메서드가 있어서 반복할 수 있는 객체
• { value, done } 구조로 값을 반환
let range = {
from: 1,
to: 5
};
range[Symbol.iterator] = function() {
return {
current: this.from,
last: this.to,
next() {
if (this.current <= this.last) {
return { done: false, value: this.current++ };
} else {
return { done: true };
}
}
};
};
for (let num of range) {
alert(num); // 1, then 2, 3, 4, 5
}
예제 코드를 기준으로 range는 이터러블 객체 range[Symbol.iterator]()의 반환값이 이터레이터 객체라고 할 수 있다.
let range = {
from: 1,
to: 5,
[Symbol.iterator]() {
this.current = this.from;
return this;
},
next() {
if (this.current <= this.to) {
return { done: false, value: this.current++ };
} else {
return { done: true };
}
}
};
물론 range 자체를 이터레이터로 만들면 코드는 더 간단해진다.
일부 Array의 헬퍼 메서드들이 Iterator의 헬퍼 메서드들과 1대1 매칭이 된다. filter 메서드를 기준으로 둘에는 어떠한 차이가 존재하는지 확인한다.
| 항목 | Array.prototype.filter | Iterator.prototype.filter |
|---|---|---|
| 대상 | 배열 | 이터러블/이터레이터 |
| 평가 시점 | 즉시 실행 | 지연 실행 |
| 반환값 | 새로운 배열 | 새 이터레이터 |
| 사용 방식 | 일반 배열에서 즉시 결과 추출 | 필요한 만큼만 값을 계산 |
| 메모리 효율 | 낮을 수 있음 (전체 배열 생성) | 높음 (필요한 만큼만 계산) |
const arr = [1, 2, 3, 4, 5];
const even = arr.filter(x => x % 2 === 0);
console.log(even); // [2, 4]
const iter = [1, 2, 3, 4, 5].values(); // 이터레이터 생성
const filtered = iter.filter(x => x % 2 === 0);
console.log(filtered.next()); // { value: 2, done: false }
console.log(filtered.next()); // { value: 4, done: false }
console.log(filtered.next()); // { value: undefined, done: true }
.next()를 호출할 때마다 조건을 확인하고 값을 계산한다.두 방식을 의사 코드로 구현해본다.
ECMAScript 2024 spec: Array.prototype.filter
Array.prototype.filter = function(callback, thisArg) {
const result = [];
for (let i = 0; i < this.length; i++) {
if (i in this) {
const val = this[i];
if (callback.call(thisArg, val, i, this)) {
result.push(val);
}
}
}
return result;
};
Iterator.prototype.filter = function (predicate) {
// this는 iterator이어야 한다
const source = this;
return {
next() {
while (true) {
const { value, done } = source.next();
if (done) return { value: undefined, done: true };
if (predicate(value)) return { value, done: false };
}
},
[Symbol.iterator]() {
return this;
}
};
};

javascript values vs array method
해당 링크의 테스트 결과를 시각화해서 확인한다.
배열의 크기가 작은 경우 큰 차이가 존재하지 않지만, 배열의 크기가 커질 수록 ops의 차이가 극단적으로 커지는 것을 확인할 수 있다.
큰 배열일 수록 지연평가를 활용했을 때 얻을 수 있는 이점이 많다.
iterable 객체
proposal-iterator-helpers와 지연평가
2025년에 자바스크립트 개발자라면 꼭 알아야 할 기능들 | GeekNews
Rust Iterators in JavaScript. Generators in JavaScript | by Andrew Burkus | Medium
[ JS ] 이터레이터, 제너레이터, 지연평가 ( Iterator, Generator, Lazy Evaluation )
Comparing: array method chaining, generator delegations, and transducing · GitHub
헬퍼