-
[Javascript] 이터러블, 제너레이터Javascript 2024. 4. 8. 11:31
이터러블 프로토콜 (Iterable Protocol)
- 반복, 순회 기능을 사용하는 주체간의 통일된 규격
- 공통 기능들: for ... of, 스프레드 문법, 배열 디스트럭쳐링
- 이터러블 :
- 이터러블이란 이터레이터를 반환하는 Symbol.iterator를 프로퍼티 키로 갖는 메서드를 가진 객체
- Symbol.iterator를 프로퍼티 키로 사용한 메서드를 직접 구현하거나, 프로토타입 체인을 통해 상속 받을 수 있음
- 위 규약을 이터러블 프로토콜, 이터러블 프로토콜을 준수한 객체를 이터러블이라고 함
- 이터러블은 for...of문으로 순회할 수 있고 스프레드 문법, 구조 분해 할당의 대상으로 사용 가능

- 키 Symbol.iterator ( well-known 심볼 ) 의 값으로 이터레이터를 반환하는 메서드를 가짐

이터레이터 프로토콜 (Iterator Protocol)
- 이터레이터란 { value, done }라는 이터레이터 리절트 객체를 반환하는 next 메서드를 소유하는 객체
- 이터레이터는 이터러블의 요소를 탐색하기 위한 포인터 역할
- 위 규약을 이터레이터 프로토콜, 이터레이터 프로토콜을 준수한 객체를 이터레이터라고 함
- 이터레이터 :
- 이터러블의 Symbol.iterator 메서드 호출시 이터레이터 프로토콜을 준수한 이터레이터 객체를 반환, 이때 이터레이트는 next 메서드를 가짐
- 이터레이트의 next 메서드는 이터러블의 각 요소를 순회하기 위한 포인터 역할로, next 메서드 호출시 순회 결과를 나타내는 이터레이터 리절트 객체를 반환
- 이터레이터 리절트 객체는 현재 순회 중인 이러터블의 값을 나타내는 value, 이터러블의 순회 완료 여부를 나타내는 done 프로퍼티를 가짐
let range = { // 객체 생성 from: 1, to: 5 }; // 1. for..of 최초 호출 시, Symbol.iterator가 호출됩니다. //아래의 메소드를 갖는 것이 이터러블 프로토콜 range[Symbol.iterator] = function() { // Symbol.iterator는 이터레이터 객체를 반환합니다. // 2. 이후 for..of는 반환된 이터레이터 객체만을 대상으로 동작하는데, 이때 다음 값도 정해집니다. return { current: this.from, last: this.to, // 3. for..of 반복문에 의해 반복마다 next()가 호출됩니다. next() { // 4. next()는 값을 객체 {done:.., value :...}형태로 반환해야 합니다. if (this.current <= this.last) { return { done: false, value: this.current++ }; // 순회 진행 } else { return { done: true }; // 순회 종료 } } }; }; // 💡 for ... of 문 사용 가능, for...of 최초 호출시, Symbol.iterator가 호출됨 for (let num of range) { console.log(num); // 1, 2, 3, 4, 5 } const rangeIterator = range[Symbol.iterator](); for (let i = 0; i < range.to ; i++) { console.log( rangeIterator.next() ); } //{done: false, value: 1} .. //배열 디스트럭쳐링 사용 가능 console.log( '첫번째, 두번째 숫자는 각각 ' + `${first}(와)과 ${second}, 나머지의 합은 ${ rest.reduce((a, b) => a + b) } 입니다.` ); //첫번째, 두번째 숫자는 각각 1(와)과 2, 나머지의 합은 12 입니다.
- 이터러블 , 이터레이터 함께 사용

- 제너레이터 : 이터레이터를 사용하여 값을 순회하는 방법을 제공, 이터러블이며 동시에 이터레이터(이터레이터를 리턴하는 함수)
제너레이터 함수/메서드 선언
- function 다음 또는 메서드명 앞에 * - 띄어쓰기 위치 무관
// 함수 선언 function* genFunc1 () { yield 'genFunc1'; } // 값으로 대입 const genFunc2 = function* () { yield 'genFunc2'; } // 객체의 메서드 const obj = { * genFunc3 () { yield 'genFunc3'; } } // 클래스의 메서드 class MyClass { * genFunc4 () { yield 'genFunc4'; } } // 테스트 console.log( genFunc1().next().value, genFunc2().next().value, obj.genFunc3().next().value, new MyClass().genFunc4().next().value, ); //genFunc1 genFunc2 genFunc3 genFunc4제너레이터 함수 정의
- 함수 실행시, 코드 블록 내부가 실행되는 것이 아닌 제너레이터 객체 반환
- 함수 내 코드들을 실행하지않고 외부 호출자에게 제어권을 양도
- function* 키워드로 선언하며 1개 이상의 yield 표현식을 포함
- 애스터리스크(*)는 function 키워드와 함수명 사이에 사용 (일관성을 위해 function 키워드 바로 뒤에 붙이는 것을 권장)
- 화살표 함수로 정의, new 연산자와 함께 생성자 함수로 호출 불가
- 함수 실행시, 코드 블록 내부가 실행되는 것이 아닌 제너레이터 객체 반환
function* genFunction () { yield '하나'; //yield는 함수의 실행을 일시적으로 정지 yield '둘'; yield '셋'; } const genObj = genFunction();// 반복 수행해 볼 것 // 💡 아래의 코드가 블록의 코드에 대한 제어권을 가짐 console.log( genObj.next() ); //{value: '하나', done: false}... {value: '둘', done: false}...{value: undefined, done: true} console.log( genObj ); // 💡 이터러블임 확인 console.log( genObj[Symbol.iterator] ); console.log([...genObj]); // (3) ['하나', '둘', '셋'] // ⚠️ 순회 후에는 재생성 필요 console.log([...genObj]); // [] // 이터러블로서는 바로 호출이 적합 console.log([...genFunction()]); // (3) ['하나', '둘', '셋'] for (const num of genFunction()) { console.log(num); } genObj = genFunction(); // 재생성
- next 메서드를 실행하면 다음 yield까지 실행 후 중지
- yield의 값을 value로 반환
- 끝까지 실행 후 done: true
yield / next
yield는 제너레이터 함수의 실행을 일시적으로 정지시키며, yield 뒤에 오는 표현식은 제너레이터의 caller에게 반환된다.
next 메소드는 { value, done } 프로퍼티를 갖는 이터레이터 객체를 반환한다.
즉, value 프로퍼티는 yield 문이 반환한 값이고 done 프로퍼티는 제너레이터 함수 내의 모든 yield 문이 실행되었는지를 나타내는 boolean 타입의 값이다.
마지막 yield 문까지 실행된 상태에서 next 메소드를 호출하면 done 프로퍼티 값은 true
출처: https://inpa.tistory.com/entry/JS-📚-제너레이터-이터레이터-강화판 [Inpa Dev 👨💻:티스토리]
'Javascript' 카테고리의 다른 글
[Javascript] Prototype 프로토타입 (0) 2024.04.09 [Javascript] 스코프와 바인딩 (0) 2024.04.09 [Javascript] Set , Map (0) 2024.04.08 [Javascript] 클래스 Class (1) 2024.04.05 [Javascript] 고차함수 메소드 (0) 2024.04.05