34.1 이터레이션 프로토콜
- 순회 가능한(iterable) 데이터 컬렉션을 만들기 위해 ESMAScript 사양에서 정의하여 미리 약속한 규칙
- 순회 가능한 데이터 컬렉션을 이터레이션 프로토콜을 준수하는 이터러블로 통일하여 for...of문, 스프레드 문법, 배열 디스트럭처링 할당의 대상으로 사용할 수 있도록 일원화
34.1.1 이터러블
- 이터러블 프로토콜을 준수한 객체
- Symbol.iterator를 프로퍼티 키로 사용한 메서드를 직접 구현 or 프로토타입 체인을 통해 상속받은 객체
const isIterable = v => v !== null && typeof v[Symbol.iterator] === 'function';
//배열,문자열,Map,Set 등은 이터러블
isIterable([]); //true
isIterable(' '); //true
isIterable(new Map()); //true
isIterable(new Set()); //true
isIterable({}); //true
- 이터러블은 for...of문으로 순회할 수 있으며, 스프레드 문법과 배열 디스트럭처링 할당의 대상으로 사용 가능
const array = [1,2,3];
//배열은 Array.prototype의 Symbol.iterator 메서드를 상속받는 이터러블
console.log(Symbol.iterator in array); //true
//이터러블인 배열은 for..of문으로 순회 가능
for(const item of array) {
console.log(item);
}
//이터러블인 배열은 스프레드 문법의 대상으로 사용 가능
console.log([...array]); //[ 1, 2, 3 ]
//이터러블인 배열은 배열 디스트럭처링 할당의 대상으로 사용 가능
const [a, ...rest] = array;
console.log(a,rest); //1 [ 2, 3 ]
- 일반 객체도 이터러블 프로토콜을 준수하도록 구현하면 이터러블이 됨
34.1.2 이터레이터
- 이터러블의 Symbol.iterator 메서드를 호출하면 이터레이터 프로토콜을 준수한 이터레이터를 반환
- 이터러블의 Symbol.iterator 메서드가 반환한 이터레이터는 next 메서드를 가짐
- 이터레이터의 next 메서드는 이터러블의 각 요소를 순회하기 위한 포인터의 역할
- next 메서드를 호출하면 이터러블을 한 단계씩 순회하며 순회 결과를 나타내는 이터레이터 리절트 객체(iterator result object)를 반환
//배열은 이터러블 프로토콜을 준수한 이터러블
const array = [1,2,3];
//Symbol.iterator 메서드는 이터레이터를 반환. 이터레이터는 next 메서드를 가짐
const iterator = array[Symbol.iterator]();
//next 메서드를 호출하면 이터러블을 순회하며 순회 결과를 나타내는 이터레이터 리절트 객체 반환
//이터레이터 리절트 객체는 value와 done 프로퍼티를 갖는 객체
console.log(iterator.next()); //{ value: 1, done: false }
console.log(iterator.next()); //{ value: 2, done: false }
console.log(iterator.next()); //{ value: 3, done: false }
console.log(iterator.next()); //{ value: undefined, done: true }
- 리절트 객체의 value 프로퍼티
: 현재 순회 중인 이터러블의 값
- 리절트 객체의 done 프로퍼티
: 이터러블의 순회 완료 여부
34.2 빌트인 이터러블
- 자바스크립트가 제공한 이터레이션 프로토콜을 준수한 객체인 빌트인 이터러블
- Array, String,Map,Set, TypeArray, arugments, DOM 컬렉션
34.3 for ... of 문
- 이터러블을 순회하면서 이터러블의 요소를 변수에 할당
for(변수선언문 of 이터러블) { ... }
- 내부적으로 이터레이터의 next 메서드를 호출하여 이터러블을 순회하며 next 메서드가 반환한 이터레이터 리절트 객체의 value 프로퍼티 값을 for...of문의 변수에 할당
for(const item of [1,2,3]) {
console.log(item); //1 2 3
}
34.4 이터러블과 유사 배열 객체
- 유사 배열 객체
: 마치 배열 처럼 인덱스로 프로퍼티 값에 접근 가능하면서 length 프로피터를 갖는 객체
: 이터러블이 아닌 일반 객체
: Symbol.iterator 메서드가 없기 때문에 for ... of문으로 순회할 수 없음
- arguments, NodeList, HTMLCollection은 유사 배열 객체이면서 이터러블
- 이터러블이 아닌 유사 배열 객체는 Array.from 메서드를 사용하여 배열로 변환 가능
34.5 사용자 정의 이터러블
34.5.1 사용자 정의 이터러블 구현
- 일반 객체도 이터레이션 프로토콜을 준수하도록 구현하면 사용자 정의 이터러블이 됨
- 이터레이션 프로토콜을 준수하도록 Symbol.iteraotr 메서드를 구현하고 Symbol.iterator 메서드가 next 메서드를 갖는 이터레이터를 반환하도록 함
- 이터레이션의 next 메서드는 done과 value 프로퍼티를 가지는 이터레이터 리절트 객체를 반환
- for...of 문은 done 프로퍼티가 true가 될 때까지 반복하며 done 프로퍼티가 true가 되면 반복을 중지
//피보나치 수열을 구현한 사용자 이터러블
const fibonacci = {
//[Symbol.iterator] 메서드를 구현
[Symbol.iterator]() {
let [pre,cur] = [0,1];
const max = 10; //수열의 최대값
//next 메서드를 소유한 이터레이터를 반환
//next 메서드는 이터레이터 리절트 객체를 반환
return {
next() {
[pre,cur] = [cur,pre+cur];
return {value:cur , done: cur>= max};
}
};
}
};
//이터러블인 fibonacci 객체를 순회할 때마다 next 메서드가 호출
for(const num of fibonacci) {
console.log(num); //1 2 3 5 8
}
34.6.2 이터러블을 생성하는 함수
- 수열을 최대값을 인수로 전달받아 이터러블을 반환하는 함수
- fibonacciFunc 함수는 이터러블을 반환
//피보나치 수열을 구현한 사용자 정의 이터러블을 반환하는 함수
//수열의 최대값을 인수로 전달받음
const fibonacciFunc = function (max) {
let [pre,cur] = [0,1];
//Symbol.iterator 메서드를 구현한 이터러블 반환
return {
[Symbol.iterator]() {
return {
next () {
[pre,cur] = [cur, pre+cur];
return {vlaue: cur, done: cur>=max};
}
};
}
};
};
//이터러블을 반환하는 함수에 수열의 최대값을 인수로 전달하면서 호출
for(const num of fibonacciFunc(10)) {
console.log(num); //1 2 3 5 8
}
34.6.3 이터러블이면서 이터레이터인 객체를 생성하는 함수
- 이터레이터를 생성하려면 이터러블의 Symbol.iterator 메서드를 호출해야함
- 이터러블이면서 이터레이터인 객체를 생성하면 Symbol.iterator 메서들르 호출하지 않아도 됨
//이터러블이면서 이터레이터인 객체
//이터레이터를 반환하는 Symbol.iterator 메서드와 이터레이션 리절트 객체를 반환하는 next 메서드를 소유
{
[Symbol.iterator] () {return this;},
next() {
return { value: any, done : boolan};
}
}
//이터러블이면서 이터레이터인 객체를 반환하는 함수
const fibonacciFunc = function (max) {
let [pre,cur] = [0,1];
//Symbol.iterator 메서드를 구현한 이터러블 반환
return {
[Symbol.iterator]() { return this;},
//next 메서드는 이터레이터 리절트 객체를 반환
next() {
[pre,cur] = [cur,pre+cur];
return {valeu:cur, done: cur>=max};
}
};
};
//iter는 이터러블이면서 이터레이터
let iter = fibonacciFunc(10);
//iter는 이터러블이므로 for..of문으로 순회 가능
for(const num of iter) {
console.log(num); //1 2 3 5 8
}
iter = fibonacciFunc(10);
//iter는 이터레이터이므로 이터레이션 리절트 객체를 반환하는 next 메서드 소유
console.log(iter.next()); //{ valeu: 1, done: false }
console.log(iter.next()); //{ valeu: 2, done: false }
console.log(iter.next()); //{ valeu: 3, done: false }
console.log(iter.next()); //{ valeu: 5, done: false }
console.log(iter.next()); //{ valeu: 8, done: false }
console.log(iter.next()); //{ valeu: 13, done: true }
36.6.4 무한 이터러블과 지연 평가
- 무한 이터러블을 생성하는 함수
- 이터러블은 지연 평가 (Jazy evaluation)을 통해 데이터를 생성
//무한 이터러블을 생성하는 함수
const fibonaccifFunc = function() {
let [pre,cur] = [0,1];
return {
[Symbol.iterator] () {return this;},
next() {
[pre,cur] = [cur,pre+cur];
return {value:cur};
}
};
};
//fibonaccifFunc 함수는 무한 이터러블을 생성
for(const num of fibonaccifFunc()) {
if(num > 10000) break;
console.log(num); //1 2 3 5 8 ... 6765
}
//배열 디스트럭처링 할당을 통해 무한 이터러블에서 3개의 요소만 취득
const [f1, f2, f3] = fibonaccifFunc();
console.log(f1,f2,f3); // 1 2 3
- fibonacciFunc 함수는 데이터 소비자인 for...of문이나 배열 디스트럭처링 할당 등이 실행되기 이전까지 데이터를 생성하지는 않음. for ... of문의 경우 이터러블을 순회할 때 내부에서 이터레이터의 next 메서드를 호출하는데 이때 데이터가 생성
=> 데이터가 필요할 때까지 데이터의 생성을 지연하다가 데이터가 필요한 순간 데이터를 생성
'JavaScript' 카테고리의 다른 글
[Deep dive] 36장 디스트럭처링 할당 (0) | 2023.08.18 |
---|---|
[Deep dive] 35장 스프레드 문법 (0) | 2023.08.18 |
[Deep dive] 33장 7번째 데이터 타입 Symbol (0) | 2023.08.17 |
[Deep dive] 32장 String (0) | 2023.08.17 |
[Deep dive] 31장 RegExp (0) | 2023.08.17 |