Index
① Iterable & Iterator 프로토콜
② for...of
vs for...in
③ 유사 배열 vs 이터러블 vs DOM 특수 객체
④ 이터레이터 vs 이터러블 vs 둘 다 되는 객체
1. Iterable & Iterate
1.1 이터러블 프로토콜(Iterable protocol)
정의: 객체가 Symbol.iterator()
메서드를 가지고 있으면 이터러블 프로토콜을 따름
목적: 객체가 반복 가능하게 하기 위해서(즉, 순회대상이 되기 위해서)
반환값: Symbol.iterator()
를 호출하면 이터레이터 객체를 반환해야 함
사용처: for...of
, 스프레드 문법(...
), 배열 구조 분해 등에서 사용가능
예시객체: Array, String, Set, Map, 사용자 정의 이터러블 등
const iterable = {
[Symbol.iterator]() {
return {
next() {
return { value: 1, done: true };
},
};
},
};
ex)
const isIterable = v => !== null && typeof v[Symbol.iterator] === 'function';
// 배열, 문자열, map, set 등은 이터러블이다.
isIterable([]); // true
isIterable(''); // true
isIterable(new Map()); // true
isIterable(new Set()); // true
isIterable({}); // false
// 예를 들어, 배열은 Array.prototype의 Symbol.iterator 메서드를 상속받는 이터러블이다. 이터러블은 for...of 문으로 순회할 수 있으며, 스프레드 문법과 배열 디스트럭처링 할당의 대상으로 사용할 수 있다.
const array = [1, 2, 3]
// 배열은 Array.prototye의 Symbol.iterator 메서드를 상속받은 이터러블이다.
console.log(Symbol.itearble in array); // true
// ✅ 이터러블인 배열은 for...of 문으로 순회 가능하다.
for(const item of array) {
console.log(item);
}
// ✅ 이터러블인 배열은 스프레드 문법의 대상으로 사용할 수 있다.
console.log([...array]); // [1, 2, 3]
1.2 이터레이터 프로토콜(Iterator protocol)
정의: 객체가 next()
메서드를 가지고 있고, 호출시 {value, done}
객체를 반환하면 이터레이터 프로토콜을 따름
목적: 이터러블에서 실제 값을 하나씩 꺼내는 역할 (반복의 포인터)
반환값: next()
는 항상 {value: any, done: boolean}
형식의 객체를 반환해야 함
사용처: for...of
등에서 내부적으로 자동 호출됨
예시객체: iterable[Symbol.iterator()]
가 가변한 객체가 대부분 해당됨
const iterable = {
next() {
return { value: 1, done: false };
},
};
비교항목 | 이터러블 프로토콜 | 이터레이터 프로토콜 |
---|---|---|
기준 메서드 | Symbol.iterator() |
next() |
역할 | “반복 가능한 객체” | “반복의 진행 상태” |
반환하는 것 | 이터레이터 객체 | {value, done} 객체 |
누가 호출? | for...of 같은 반복 구문이 호출 |
반복 구문 내부에서 자동 호출 |
사용자 정의 시 | 반복 대상 객체의 Symbol.iterator() 구현 |
반환되는 이터레이터 객체의 next() 구현 |
ex)
// 배열은 이터러블 프로토콜을 준수한 이터러블이다.
const array = [1, 2, 3];
// Symbol.iterable 메서드는 이터레이터를 반환한다.
const iterable = array[Symbol.iterator]();
// Symbol.iterator 메서드가 반환한 이터레이터는 next 메서드를 갖는다.
console.log("next" in iterable); // true
console.log(iterable.next()); // {value: 1, done: false}
console.log(iterable.next()); // {value: 2, done: false}
console.log(iterable.next()); // {value: 3, done: false}
console.log(iterable.next()); // {value: 4, done: true}
2. for...of
vs for...in
무슨 차이가 있는가
for...in
은 단지 키(key)를 가져오는 문법
for...of
는 자바스크립트의 반복 구문 중 유일하게 Symbol.iterator()
를 직접호출해서 이터레이터를 사용하는 문법
const arr = ["a", "b", "c"];
for (const key in arr) {
console.log("for...in:", key); // '0', '1', '2' (문자열 인덱스)
}
for (const value of arr) {
console.log(`for...of`, value); // 'a', 'b', 'c' (실제 값)
}
3. 유사배열객체 vs 이터러블 vs arguments, NodeList, HTMLCollection

iterable_compare table
Jay Tak
3.1 유사배열객체(Array-like Object)
조건:
length
속성 있음- 숫자 인덱스로 접근 가능(예:
obj[0]
) - 하지만
Symbol.iterator()
가 없으면for...of
불가
const arrayLike = {0: 'a', 1: 'b', length: 2},
console.log(arrayLike[0]); // 'a'
- 유사배열객체는
Symbol.iterator()
가 있을수도 있고, 없을수도 있습니다.
// 1. Symbol.iterator가 없는 유사배열객체 (이터러블x)
const notIterable = {
0: 'a',
1: 'b',
length: 2
};
console.log(notIterable[0]); // 'a' ✅
console.log(notIterable.length); // 2 ✅
for (const item of notIterable) {
// ❌ TypeError: notIterable is not iterable
}
---------------------------------------------------------------------------------------------
// 2. Symbol.iterator가 있는 유사배열객체 (이터러블o)
const iterableArrayLike = {
0: 'x',
1: 'y',
length: 2,
[Symbol.iterator]() {
let i = 0;
return {
next: () => {
return i < this.length
? { value: this[i++], done: false }
: { done: true };
}
};
}
};
console.log([...iterableArrayLike]); // ✅ ['x', 'y']
3.2 이터러블 객체(Iterable Object)
조건:
Symbol.iterator()
메서드가 있음for...of
, 전개 연산자(...
), 구조 분해 할당 등에서 사용 가능
const iterable = {
[Symbol.iterabor]() {
let i = 0;
return {
next() {
return i < 3 ? { value: i++, done: false } : { done: true };
},
};
},
};
3.3 arguments
function example() {
for (const arg of arguments) {
console.log(arg); // 가능 ✅ ES6 이후 가능
}
}
3.4 NodeList
const nodes = document.querySelectorAll("div");
for (const node of nodes) {
console.log(node); // ✅ 가능
}
3.5 HTMLCollection
const elements = document.getElementsByTagName("p");
for (const el of elements) {
console.log(el); // ✅ 가능
}
4. 이터레이터 vs 이터러블 vs 이터러블이자 이터레이터를 생성
4.1 이터레이터
- 이터레이터만 생성하는 함수
next()
메서드만 있고,Symbol.Iterator()
는 없음 →for...of
불가
function makeIterator() {
let i = 0;
return {
next() {
return i < 3 ? { value: i++, done: false } : { done: true };
},
};
}
const iter = makeIterator();
console.log(iter.next()); // { value: 0, done: false }
console.log(iter.next()); // { value: 1, done: false }
console.log(iter.next()); // { value: 2, done: false }
console.log(iter.next()); // { done: true }
// ❌ for...of 사용 불가
// for (const val of iter) { console.log(val); } → TypeError
🧐 Q. 어떤 경우에 적합하게 사용할까?
내부적으로 직접 next()
를 호출해 반복 제어하고 싶을때
// 1.1 수동으로 반복처리기 만들때
function makeIterator(max) {
let i = 0;
return {
next() {
return i < max ? { value: i++, done: false } : { done: true };
},
};
}
// 1.2 수동으로 반복하기
const iter = makeIterator(5);
let result = iter.next();
while (!result.done) {
console.log(result.value); // 출력: 0, 1, 2, 3, 4
result = iter.next(); // 수동으로 다음 값 요청
}
4.2 이터러블
- 이터러블만 생성하는 함수
Symbol.iterator()
는 있지만next()
는 반환된 객체만 있음 → 반복할 수 있지만 직접 next는 호출못함
function makeIterable(max) {
return {
[Symbol.iterator]() {
let i = 0;
return {
next() {
return i < max ? { value: i++, done: false } : { done: true };
},
};
},
};
}
const iterable = makeIterable(3);
for (const val of iterable) {
console.log(val); // 0, 1, 2
}
// ❌ iterable.next()는 없음 → 이터레이터는 별도로 꺼내야 함
// console.log(iterable.next()); → Error
🧐 Q. 어떤 경우에 적합하게 사용할까?
for...of
, ...
, Array.from()
등 순회 기반 문법을 자유롭게 사용하고 싶을때
// 2.1 페이징 API 시뮬레이터
function fakeApi(page) {
const data = {
1: ['A': 'B'],
2: ['C': 'D'],
3: ['E'],
4: [] // 마지막 페이지
};
return data[page] || [];
}
// 2.2 이터러블 페이지네이터
function createPaginator(maxPages) {
return {
[Symbol.iterator]() {
let currentPage = 1;
return {
next() {
if (currentPage > maxPages) return {done: true};
const data = fakeApi(currentPage++);
return data.length ? {value: data, done: false} : {done: true};
}
};
}
};
}
for (const pageData of createPaginator(4)) {
console.log('Page:', pageDate);
}
// 출력:
// Page: ['A', 'B']
// Page: ['C', 'D']
// Page: ['E']
4.3 이터러블이자 이터레이터인 객체를 생성하는 함수
- 이터러블이자 이터레이터인 객체를 생성하는 함수
Symbol.iterator()
가this
를 반환 →for...of
와next()
둘 다 가능- 하지만 한 번만 순회 가능(소진됨)
function makeIterableIterator(max) {
let i = 0;
return {
[Symbol.iterator]() {
return this;
},
next() {
return i < max ? { value: i++, done: false } : { done: true };
},
};
}
const iterBoth = makeIterableIterator(3);
for (const val of iterBoth) {
console.log(val); // 0, 1, 2
}
for (const val of iterBoth) {
console.log(val); // ❌ 출력 없음: 이터레이터는 소진됨
}
// ✅ 직접 next()도 호출 가능
const iter3 = makeIterableIterator(2);
console.log(iter3.next()); // { value: 0, done: false }
console.log(iter3.next()); // { value: 1, done: false }
console.log(iter3.next()); // { done: true }
🧐 Q. 어떤 경우에 적합하게 사용할까?
간단한 반복 작업을 만들고 for...of
, next()
를 모두 지원하고 싶을 때
// 3.1 JSON 데이터 처럼 한 번만 읽고 순회할 수 있는 스트림을 이터러블로 구현한 예제
function createOneTimeStream(dataArray) {
let index = 0;
return {
[Symbol.iterator]() {
return this; // 자기 자신이 이터레이터이자 이터러블
},
next() {
return index < dataArray.length
? { value: dataArray[index++], done: false }
: { done: true };
},
};
}
const stream = createOneTimeStream(["🧊", "🔥", "💧"]);
for (const item of stream) {
console.log("🚚 received:", item);
}
// 🚚 received: 🧊
// 🚚 received: 🔥
// 🚚 received: 💧
for (const item of stream) {
console.log("❌ should not appear:", item); // 출력 없음 – 이미 소진됨
}