1. 탐구
iterable & iterator
- iterable : 자료를 반복할 수 있는 객체
- iterable 규약을 따르는 객체
- iterator를 리턴하는
[Symbol.iterator]()메서드를 가진 객체
- iterator :
{value:값,done:true/false}형태의 iterator 객체를 리턴하는 next()메서드를 가진 객체- next메서드로 순환할 수 있는 객체
- iterable 프로토콜 / iterator프로토콜 : iterable을 for..of, 전개연산자, 비구조화 등 iterable이나 iterator 프로토콜을 따르는 연산자들과 함께 동작하도록 하는 약속된 규약
Iterator 직접 만들기
let range = { // 1) 객체 생성
from: 1,
to: 5
};
range[Symbol.iterator] = function() { // 2) 새로운 키:밸류 를 추가한다. 키는 변수형태, 밸류는 함수이다.
return { // 객체를 리턴한다. 그런데 좀 특벽할 형태의 객체
current: this.from,
last: this.to,
next() { // 3) next() 정의
if (this.current <= this.last) {
return { done: false, value: this.current++ };
// 4) {value : 값 , done : true/false} 형태의 이터레이터 객체를 리턴합니다.
} else {
return { done: true };
}
}
};
};
range의 Symbol.iterator 객체는 클로저 next()를 리턴한다. 이 클로저는 리턴했을 때의 실행 컨텍스트에 있는 변수인 current와 last에 접근이 가능하다.
여기서 range는 Symbol.iterator메서드를 가진 iterable 객체이다. 여기서 Symbol.iterable은 {value,done}을 리턴하는 next()메서드를 가진 객체를 말한다.
유사배열 vs iterable
- iterable :
Symbol.iterator메서드가 구현된 객체 - 유사배열 : index와 length 프로터피가 있어서 배열처럼 보이는 객체
- Map자료형, DOM에서 반환한 배열, argument배열 : 이터러블 작업이 마쳐진 유사배열
모든 유사배열은 Symbol.iterator메서드가 있지 않는 한 iterable객체가 아니다. 유사배열을 iterable객체로 만들기 위해서는 Array.from메서드를 이용해 진짜 배열로 만들어준다.
const obj = {
0: 1,
1: 2,
2: 3,
length: 3,
};
const array = Array.from(obj);
console.log(array);
for (const it of array) console.log(it);
단, object의 key값이 0부터 시작하는 index여야하고, length값도 가지고 있어야 한다.
- 문자열은 이터러블인 유사배열이다.
Generator
: 이터레이터를 만드는 함수
- 일반 함수는 하나의 값만을 반환하지만, 여러 개의 값을 필요에 따라 하나씩 반환(yield)할 수 있다
- 제너레이터와 이터러블 객체를 함께 사용하면 손쉽게 데이터 스트림을 만들 수 있다
Generator 함수
function* generateSequence() {
yield 1;
yield 2;
return 3;
}
cosnt generator = generateSequence();
alert(generator); // [object Generator]
제너레이터 함수는 일반 함수와 다르게, 호출하면 코드가 실행되지 않고 실행을 처리하는 특별한 객체 ‘제너레이터 객체’가 반환된다.
next()
: 가장 가까운 yield <value> 문을 만날 때까지 실행이 지속된다
- 제너레이터의 주요 메서드
value와done두 프로퍼티를 가진 객체를 반환한다
function* gen() {
yield 1;
yield 2;
return 3;
}
const iter = gen();
console.log(iter); // {[Generator]}
console.log(iter.next()) // { value: 1, done:false }
console.log(iter.next()) // { value: 2, done:false }
console.log(iter.next()) // { value: 3, done:true }
console.log(iter.next()) // { value: undefined, done:true }
- 제너레이터 = 이터러블이다. 즉, 제너레이터 함수를 통해 생성한 제너레이터 객체는 next()메서드를 통해 순회할 수 있는 이터러블 객체이다.
Generator로 Iterator 직접 만들기
let range = {
from:1,
to:5,
*[Symbol.iterator](){
for(let value = this.from;value<=this.to;value++){
yield value;
}
}
}
console.log([...range]) // [1,2,3,4,5]
- rangeSymbol.iterator는 제너레이터(이터러블 객체)를 반환한다