사용자 정의 이터러블에 대해 알아보자!
먼저,
앞서 알아보았던 이터러블과 이터레이터에 대해 다시 떠올려 보자.
이터러블은 이터레이션 프로토콜을 준수하도록 Symbol.iterator 메서드를 구현하거나 프로토타입 체인을 통해 상속 받은 객체이다.
이터러블의 Symbol.iterator 메서드가 반환한 이터레이터는 next 메서드를 갖는다.
이터레이터의 next 메서드는 done과 value 프로퍼티를 갖는 이터레이터 리절트 객체 반환,
for ... of 문은 done 프로퍼티가 true가 될 때까지 반복하며 done 프로퍼티가 true가 되면 반복 중지,
이터러블은 for ... of 문 뿐만 아니라 스프레드 문법, 배열 디스트럭처링 할당에도 사용할 수 있다.
사용자 정의 이터러블
일반 객체도 이터레이션 프로토콜을 구현하면 사용자 정의 이터러블이 된다.
사용자 정의 이터러블은 이터레이션 프로토콜을 준수하도록 Symbol.iterator 메서드를 구현하고 Symbol.iterator 메서드가 next 메서드를 갖는 이터레이터를 반환하도록 한다.
또한 갖는 특성은 위에서 언급한 일반적인 이터러블과 동일하다.
피보나치 수열을 구현한 사용자 정의 이터러블을 만들어 보자.
const fibonacci = {
[Symbol.iterator]() { // Symbol.iterator 메서드를 구현하여 이터러블 프로토콜 준수
let [pre, cur] = [0, 1]; // 배열 디스트럭처링 할당
const max = 10; // 수열의 최대값
return { // next 메서드를 소유한 이터레이터를 반환
next() { // next 메서드: 리절트 객체 반환
[pre, cur] = [cur, pre + cur];
return { value: cur, done: cur >= max }; // 이터레이터 리절트 객체 반환
}};}
};
for (const num of fibonacci) {
console.log(num); // 1 2 3 5 8
}
피보나치 이터러블은 내부에 수열의 최대값 max를 가지고 있다.
=> 수열의 최대값은 고정값으로 외부에서 전달한 값으로 변경할 수 없다.
이터러블을 생성하는 함수
수열의 최대값을 인수로 전달 받아 이터러블을 반환하는 함수를 만들어 수정한 경우이다.
const fibonacciFunc = function (max) {
let [pre, cur] = [0, 1];
return {
[Symbol.iterator]() {
return {
next() {
[pre, cur] = [cur, pre + cur];
return { value: cur, done: cur >= max };
}};}};
};
for (const num of fibonacciFunc(10)) {
console.log(num); // 1 2 3 5 8
} // 이터러블을 반환하는 함수에 수열의 최대값을 인수로 전달하며 호출
위 함수는 이터러블을 반환한다.
이터러블이면서 이터레이터인 객체를 생성하는 함수
이터레이터를 생성하려면 이터러블의 Symbol.iterator 메서드를 호출해야 한다.
const iterator = iterable[Symbol.iterator]();
이터러블이면서 이터레이터인 객체를 생성하면 Symbol.iterator 메서드를 호출하지 않아도 된다.
{
[Symbol.iterator]() { return this; },
next() {
return { value: any, done: boolean };
}
}
위는 Symbol.iterator 메서드와 next 메서드를 소유한 이터러블이면서 이터레이터이다.
Symbol.iterator 메서드는 this를 반환하므로 next 메서드를 갖는 이터레이터를 반환한다.
이를 이용하여 피보나치 함수를 이터러블이면서 이터레이터인 객체를 생성하여 반환하는 함수로 변경하자.
const fibonacciFunc = function (max) {
let [pre, cur] = [0, 1];
return {
[Symbol.iterator]() { return this; },
next() {
[pre, cur] = [cur, pre + cur];
return { value: cur, done: cur >= max };
}};
};
let iter = fibonacciFunc(10); // iter는 이터러블이면서 이터레이터
for (const num of iter) { // iter는 이터러블이므로 for ... of 문으로 순회 가능
console.log(num); // 1 2 3 5 8
}
iter = fibonacciFunc(10);
무한 이터러블과 지연 평가
무한 수열을 구현하기 위해 무한 이터러블을 생성하는 함수
const fibonacciFunc = function () {
let [pre, cur] = [0, 1];
return {
[Symbol.iterator]() { return this; },
next() {
[pre, cur] = [cur, pre + cur];
return { value: cur };
}};
};
for (const num of fibonacciFunc()) { // fibonacciFunc 함수는 무한 이터러블 생성
if (num > 10000) break;
console.log(num); // 1 2 3 5 8 ... 4181 6765
}
const [f1, f2, f3] = fibonacciFunc();
console.log(f1, f2, f3); // 1 2 3
위 예제의 이터러블은 지연 평가를 통해 데이터를 생성한다.
지연 평가
데이터가 필요할 때까지 데이터의 생성을 지연하다가 데이터가 필요한 순간 데이터 생성
=> 평가 결과가 필요할 때까지 평가를 늦추는 기법
for ... of 문이나 배열 디스트럭처링 할당 등이 실행되기 전까지 데이터를 생성하지 않는다.
(for ... of 문의 경우, next 메서드가 호출되기 전까지는 데이터를 생성하지 않는다.)
지연평가를 사용하면 불필요한 데이터를 미리 생성하지 않고 필요한 데이터를 필요한 순간에 생성하므로 빠른 실행 속도를 기대 할 수 있고 불필요한 메모리를 소비하지 않으며 무한도 표현할 수 있다는 장점이 있다.
본 게시글은 모던자바스크립트 Deep Dive - 자바스크립트의 기본 개념 책을 읽고 정리했습니다.
더 자세한 내용은 책을 구매해보시길 권장드립니다!
'TIL > JS' 카테고리의 다른 글
자바스크립트 복습 (0) | 2023.05.31 |
---|---|
조금 어려운 for ... of, for ... in, 유사 배열 객체 (0) | 2023.03.21 |
조금 어려운 이터러블, 이터레이터 (0) | 2023.03.21 |
아주 중요한 배열 - 메서드 (0) | 2023.03.08 |
아주 쉬운 배열 - 참조, 추가, 갱신, 삭제 (0) | 2023.03.08 |
댓글