반복 처리가 가능한 객체를 의미하며, next() 라는 메소드를 가진다.
이때 next() 는 {value : 값 , done : true/false} 형태의 객체를 리턴한다.
[Symbol.iterator] 라는 key 값의 value로서 정의되어있다.
💡 예시로 만든 이터레이터 함수
const customIter = (() => {
let current = 1;
const max = 5;
return {
next() {
return { value: current++, done: current > max + 1 };
}
}
})();

1) customIter 함수를 실행시킨다.
2) next() 메소드를 반환하는데, 이 메소드는 done의 값이 true가 될 때까지 value 값을 업데이트하며 이터러블 객체를 만든다.
3) done=true 이면 반복이 종료되었다는 것을 말한다.
const obj = { name: 'o', id: 1 }
console.log([...obj]) // Type '{ name: string; id: number; }' must have a '[Symbol.iterator]()' method that returns an iterator.
const obj = {
[Symbol.iterator]() {
let cur = 1;
const max = 5;
return {
next() {
return { value: cur++, done: cur > max + 1 };
},
};
},
name: 'o',
id: 1,
6: 'test',
};
console.log([...obj]) // (5) [1, 2, 3, 4, 5]
console.log({ ...obj }) // {6: 'test', name: 'o', id: 1, Symbol(Symbol.iterator): ƒ}
해당 코드는 이터러블이 아닌 평범한 객체를 [Symbol.iterator]()을 사용해 이터러블로 만드는 코드이다.
[Symbol.iterator] 을 key로, 그리고 이터레이터 함수를 value 값으로 넣어준다.
여기서 리턴 부분인 return { next() {return { value: cur++, done: cur > max + 1 }; }, };가 이터레이터가 된다.
max 값인 5까지만 반복하여 1, 2, 3, 4, 5 로 구성된 이터러블 객체를 만들 것이다.
+)

콘솔로 객체를 츨력해보면 [Symbol.iterator]가 추가된 것을 확인할 수 있다!
💡 for of 구문으로 반복해보기

이제 obj 객체는 이터러블이기 때문에 for of 구문을 사용해서 반복할 수 있다. for in 문을 사용하면 객체의 key 값이 나오는데, for of 구문을 사용하면 이터레이터로 만든 1부터 5까지가 출력되는 이유가 무엇일까?
➡️ for of 가 [Symbol.iterator]를 호출하여 이터레이터를 실행시키는 방식으로 동작하기 때문이다.
next()메서드를 호출한다.next()의 반환 값은 {done: Boolean, value: any}와 같은 형태이어야 한다. 그래야 순회가 된다. done=true는 반복이 종료되었음을 의미한다. done=false일땐 value에 다음 값이 저장된다. 이런 식으로 요소를 순회한다.const iterable = {
[Symbol.iterator]() {
let cur = 1;
const max = 5;
return {
next() {
return { value: cur++, done: cur > max + 1 };
},
};
},
};
const iterator = iterable[Symbol.iterator]();
let result = iterator.next();
result = iterator.next();
console.log(result) // {value: 2, done: false}
Array.isArray(iterable) // false
Array.isArray(Array.isArray([...iterable])) // true
iterable 은 [Symbol.iterator] 을 key로, 그리고 이터레이터 함수를 value 값으로 가진다.
하지만 이터레이터 자체는 반복 후 배열을 생성하여 저장하진 않는다.
클로저를 통해 current 값을 참조하고 있을 뿐이다.
result 라는 변수에 iterator.next()를 할당하여 한 번 실행한 후 콘솔에 result를 출력해보면, {value: 2, done: false} 리턴값이 그대로 출력된다.
따라서 iterable 자체는 아직 배열이 아니며, 배열을 만들고 싶다면 스프레드 연산자를 이용해 배열로 만들어줘야 한다.
💡 스프레드 연산자는 [Symbol.iterator]라는 키가 있는지 확인하고 있다면 그 키에 해당하는 함수를 계속 실행한다. (value값 업데이트)
그리고 거기서 나온 데이터를 새로운 배열에 저장한다!
즉 이터레이터가 품고있는 함수에 따라 출력되는 값이 달라지고, 배열은 그 모든 값을 이터레이터를 순환시켜 저장하여 만들어지게 된다.
✅ 스프레드 연산자
ES6에 추가된 문법으로, Array, Map, Set, String 등의 원소를 나열하여 복사할 때 사용된다.
얇은 복사를 수행하기 때문에 객체의 참조값(메모리 주소값)을 동일하게 참조하는 방식으로 복사한다.
배열의 스프레드 연산자와 객체의 스프레드 연산자의 구동 방식이 다른데,
- 배열에서 사용 ➡️ 이터러블을 사용해서 요소를 반복하고 숫자 순서를 유지하는데 중점을 두고 복사
- 객체에서 사용 ➡️ Object.assign과 같이 반복하지 않고 그냥 얕은 복사 (객체의 키에는 순서가 없기 때문)
const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
이건 우리가 흔히 아는 배열이다.
배열의 자료구조상, 요소 10개에 해당하는 만큼의 메모리가 필요하다.
const makeArray = {
[Symbol.iterator]() {
let cur = 1;
const max = 10;
return {
next() {
return { value: cur++, done: cur > max + 1 };
},
};
}
};
const makedArray = [...makeArray]
console.log(makedArray) // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
만약 이터레이터를 활용해서 같은 배열을 만들고 싶다면 이런 코드를 작성하면 된다.
그런데 이때는 cur, max 두 변수에 해당하는 메모리만 사용하면 된다.
배열 자체를 만드는 것은 스프레드 연산자가 이터레이터 함수를 반복 순회할 때이다.
➡️ 다뤄야 하는 데이터의 양이 매우 많을 때는 배열보다 이터레이터가 훨씬 효율적일 수 있다!
출처
[JS] 📚 이터러블 & 이터레이터 - 💯완벽 이해
[JavaScript] 이터레이터(Iterator)와 배열(Array)의 차이점