Section 10. 자바스크립트 이터러블
I. 이터러블 프로토콜 iterable protocol
- 반복, 순회 기능을 사용하는 주체간의 통일된 규격이다.
- 공통 기능들 : for ... of, 스프레드 문법, 배열 디스트럭쳐링
이터러블 iterable - 이터러블 프로토콜을 준수하는 객체
- 배열, 문자열, Set, Map, arguments 등 ...
- 키 Symbol.iterator (well-known 심볼)의 값으로 이터레이터를 반환하는 메서드를 가진다.
*Symbol.iterator같이 잘 알려져서 많은 것들의 식별자로 사용되는 것을 well-known 심볼이라 한다.
배열 하나를 출력해보자.
[]
그리고 콘솔에서 그걸 펼쳐보면 다음과 같다.
프로토타입 밑에 Symbol.iterator를 키로하는 어떤 함수가 들어있는 것을 볼 수 있다.
이 프로퍼티가 이터레이터의 핵심이다.
console.log(
[][Symbol.iterator],
''[Symbol.iterator],
new Set()[Symbol.iterator],
new Map()[Symbol.iterator]
);
배열, 문자열, Set, Map에 대한 Sysmbol.iterator의 값을 출력해봤다. 출력문은 다음과 같다.
공통적으로 어떤 함수들이 출력 되는 것을 볼 수 있다.
이런 함수들은 이터러블이 아닌 함수에는 존재하지 않는다.
// 다른 타입의 인스턴스에는 없음
console.log(
(1)[Symbol.iterator],
(true)[Symbol.iterator],
{ x: 1 }[Symbol.iterator]
); //undefined undefined undefined
이 함수들을 실행 괄호 ()를 붙여서 실행해보면
console.log(
[][Symbol.iterator](), //Array Iterator {}
''[Symbol.iterator](), //StringIterator {}
new Set()[Symbol.iterator](), //SetIterator {}
new Map()[Symbol.iterator]() //MapIterator {}
);
각각 해당하는 자료형의 이터레이터를 반환하는 것을 알 수 있다.
II. 이터레이터 iterator
next 메서드를 통해 이터러블을 순회하며 값을 반환한다.
const arr = [1, 'A', true, null, {x: 1, y: 2 }];
const arrIterator = arr[Symbol.iterator]();
console.log(arrIterator);
arr의 심볼 이터레이터에 접근해서 arrIterator를 뽑아냈다.
그리고 그것을 출력해보면 next()라는 함수를 가지고 있는 것을 볼 수 있다.
arr[Symbol.iterator]()를 통해서 반환된 Array Iterator 객체는 next라는 함수(기능)를 가지고 있는 것이다.
이 기능을 이용하면 arr의 요소들을 차례대로 뽑아낼 수 있다.
arrIterator.next(); //{value: 1, done: false}
arrIterator.next(); //{value: 'A', done: false}
arrIterator.next(); //{value: true, done: false}
arrIterator.next(); //{value: null, done: false}
arrIterator.next(); //{value: {…}, done: false}
arrIterator.next(); //{value: undefined, done: true}
이터레이터 프로토콜 iterator protocol
next 메서드의 반환 객체 내 요소는 다음과 같다
- value - 해당 차례에 반환할 값
- done - 순회 종료 여부 (마지막 값 반환 다음 차례부터)
III. 이터러블 만들어보기
주사위를 열 번 굴리는 이터러블
const diceTenTimes = {
// ⭐️ 아래의 메서드를 갖는 것이 이터러블 프로토콜
[Symbol.iterator] () {
let count = 0;
let maxCount = 10;
// ⭐️ 이터레이터(next 메서드를 가진 객체)을 반환
return {
next () {
return {
value: Math.ceil(Math.random() * 6),
done: count++ >= maxCount
}
}
}
}
}
diceTenTimes라는 객체를 하나 만들었다.
이 객체에 Symbol.iterator를 키로 하려면 [ ]를 써줘야 한다. 거기에 실행 괄호가 붙어서 심볼 이터레이터라는 메서드가 실행 된다.
이 메서드는 이터레이터 객체를 반환한다. 그 객체에는 next라는 함수가 있고 그 함수가 반환하는 것은
value: Math.ceil(Math.random() * 6),
done: count++ >= maxCount
이것이 되는 것이다.
실행을 해보면 다음과 같다
const diceIterator = diceTenTimes[Symbol.iterator]();
for (let i = 0; i < 12; i++) {
console.log(
diceIterator.next()
);
}
여기서 next의 done 프로퍼티가 true를 반환 했는데도 계속 출력된 이유는 for문의 종료 조건때문이다.
for ... of 문도 사용이 가능하다.
// 💡 for ... of 문 사용 가능
for (const num of diceTenTimes) {
console.log(num);
}
for 문과는 다르게 딱 10번 출력된 것을 볼 수 있다.
스프레드 문법도 사용 가능하다.
const diceResults = [...diceTenTimes];
console.log(diceResults); //[5, 1, 5, 4, 3, 3, 4, 1, 1, 2]
*이 예시는 제너레이터로 보다 간편하게 구현이 가능하다.