Chapter12. 요약
이터레이터
for(요소 of 객체)
루프와...
분해 연산자는 이터러블 객체 와 함께 사용할 수 있습니다.- 이터러블 객체를 반환하는, 심벌 이름 [Symbol.iterator] 메서드를 가진 객체는 이터러블입니다.
- 이터레이터 객체에는 순회 결과 객체를 반환하는 next( ) 메서드가 있습니다.
- 순회 결과 객체에는 다음 순회 값이 있으면 그 값을 보유하는 value 프로퍼티가 있습니다.
{value: 이터레이터 값, done: false }
- 순회가 완료됐다면 결과 객체에는 값이 true인 done 프로퍼티가 반드시 있어야 합니다.
{value: undefined, done: true}
- 순회 결과 객체를 반환하는 next() 메서드가 포함된 객체를 반환하는
[Symbol.iterator]()
메서드를 정의해 직접 이터러블 객체를 만들 수 있습니다.
- 이터레이터 인자를 받아 이터레이터 값을 반환하는 함수 역시 만들 수 있습니다.
제너레이터
- function이 아니라 function*으로 정의 된 제너레이터 함수로도 이터레이터를 만들 수 있습니다.
- 제너레이터 함수를 호출하면 함수 바디가 즉시 실행되지는 않으며 반환 값은 이터러블인 이터레이터 객체입니다.
- 이터레이터의
next()
메서드를 호출할 때마다 제너레이터 함수의 다른 코드 덩어리가 실행됩니다.- 제너레이터 함수는 yield 연산자를 사용해 이터레이터가 반환할 값을 지정할 수 있습니다.
- 제너레이터 함수는 next( ) 를 호출할 때마다 다음 yield 표현식을 만날 때까지 실행됩니다.
- 이터레이터가 반환하는 값은 yield 표현식의 값입니다.
- yield 표현식이 더 없으면 제너레이터 함수는 실행을 종료하고 순회도 완료됩니다.
〖자바스크립트 완벽 가이드〗 - 408 ~ 409p
Iteration Interface는 다음 3가지로 이루어져 있다.
① 이터러블(Iterable) 객체
: 배열, 세트, 맵과 같은 순회할 수 있는 타입의 객체
② 이터레이터(Iterator) 객체
: 순회를 수행하는 객체 자체
③ 이터레이션 결과(Iterator Result) 객체
: 각 순회 단계의 결과를 담은 객체
/* 배열도 이터러블이다. */
const arr = [1, 2, 3];
const i = arr[Symbol.iterator]();
i.next(); // { value: 1, done: false }
i.next(); // { value: 2, done: false }
i.next(); // { value: 3, done: false }
i.next(); // { value: undefined, done: true }
배열, 형식화 배열, 문자열, Set과 Map 객체는 모두 이터러블이다.
...
스프레드 연산자를 사용할 수 있다. for of 루프
로 순회할 수 있다./* 이터러블로 for 반복문 표현하기 */
let iterable = [1];
let iterator = iterable[Symbol.iterator](); // 이터레이터 객체 반환
// 이터러블 객체를 순회하는 for 루프 문
for(let result = iterator.next(); // 초기값
!result.done; // done 프로퍼티 값이 true가 되기 전까지
result = iterator.next()){ // 다음 순회 호출
console.log(result.value); // 1
console.log(result.done); // false
}
이름이 Symbol.iterator 인 메서드를 가지고 있어야하며,
이터레이터 객체
를 반환해야 한다.
이터레이터 객체는 next() 메서드를 가지고 있어야 한다.
next() 메서드는 반드시 value 프로퍼티와 done: false(또는 true) 프로퍼티를 가지고 있는 이터레이션 결과(Iterator Result) 객체
를 반환해야 한다.
// 값을 미리 만들어두지 않고, next()로 호출될 때마다 실행한다.
function* fn(){
let index = 0;
while(true){
yield index++;
}
}
const a = fn();
a.next(); // {value: 2, done: false}
a.next(); // {value: 3, done: false}
a.next(); // {value: 3, done: false}
함수를 호출해도 while(true)문이 무한 반복되지 않고,
next()로 값을 불러올 때만 실행한다.
function* fn() {
console.log(1);
yield 1;
console.log(2);
console.log(3);
yield 2;
return "finish";
}
const a = fn();
a // fn {<suspended>}
/* 함수 객체만 반환되고 함수 본문은 실행되지 않았다. */
a.next(); // 1 /* console.log에서 반환된 값 */
// {value: 1, done: false} /* yield에서 반환된 값*/
a.next(); // 2
// 3
// {value: 2, done: false}
a.next(); // {value: 'finish', done: true}
/* done: true 이후 더 호출해도 더이상 yield값이 없으므로 value는 undefined이다.*/
a.next(); // {value: undefined, done: true}
next 메서드로 가장 가까운 yield 값을 호출하고 다음 next가 호출될 때까지 함수의 실행을 멈출 수 있다.
function* fn() {
const num1 = yield "첫 번째 숫자 입력"; // ❶ num1에 할당 전 yield 에서 멈춤
console.log(num1);
const num2 = yield "두 번째 숫자 입력"; // ❷ : ❶ 이후로 실행 후 num2 할당 전 yield에서 멈춤
console.log(num2);
return num1 + num2; // ❸ : ❷ 이후로 실행 후 종료
}
const j = fn();
j.next(); /* ❶ */
// {value: '첫 번째 숫자 입력', done: false}
j.next(7); /* ❷ num1에 7 할당 */
// 7 ← num1 콘솔 출력
// {value: '두 번째 숫자 입력', done: false}
j.next(9); /* ❸ num2에 9 할당해서 num1 + num2 = 16 리턴 */
// 9 ← num2 콘솔 출력
// {value: 16, done: true}
next() 메서드에 아규먼트를 전달해서 value 값을 입력받을 수도 있다.
function* fn() {
console.log(1);
yield 1;
console.log(2);
console.log(3);
yield 2;
console.log(4);
yield 3;
return "finish";
}
const a = fn();
a.next(); // 1
// {value: 1, done: false}
/* 호출 즉시 함수 실행이 종료된다. */
a.return('END'); // {value: 'END', done: true}
a.next(); // {value: undefined, done: true}
return() 메서드를 호출하는 즉시 {done: true}
가 되며, 그 이후 next() 메서드를 실행해도 {value: undefined, done: true}
가 리턴된다.
function* fn() {
try{
console.log(1);
yield 1;
console.log(2);
console.log(3);
yield 2;
console.log(4);
yield 3;
return "finish";
} catch(err){
console.log(err);
}
}
const a = fn();
a.next(); // 1
// {value: 1, done: false}
/* Error를 처리 후 함수가 종료된다.*/
a.throw(new Error('error')); // Error: error
a.next(); // {value: undefined, done: true}
호출 즉시 에러 처리 후 {done: true} 가 된다.