1. Iterable protocol
1) Iteration
“반복”이라는 의미를 가지고 있다. 모든 애플리케이션은 “순차, 분기, 반복" 3가지로 이루어져있다. 반복은 애플리케이션을 구성하는 3가지 요소 중 하나인만큼 개발을 하는 과정에서 빈번하게 수행되는 행위다.
2) Protocol
“규약"을 의미한다. 그리고 Iterable은 “반복 가능한”이란 의미를 갖는다. 따라서 자바스크립트에서 말하는 Iterable protocol이란 “반복 가능한 자바스크립트 객체들을 정의하는 규약"이라고 할 수 있다.
이러한 Iterable protocol은 우리가 알게 모르게 사용해오고 있었다. 자바스크립트에서 사용하는 for of 문법, Spread Operator([...arr] ), 배열 구조분해할당 등의 문법은 내부적으로 Iterator protocol을 통해서 동작하고 있다. 그리고 String, Array등의 자바스크립트 빌트인 객체들은 기본적으로 Iterable protocol을 충족하기에 우리가 자연스럽게 위와 같은 문법을 사용할 수 있었던 것이다.
Iterable protocol을 충족하는 객체를 iterable이라고 한다.
3) iterable 이 되기 위한 조건
- 객체는 [Symbol.iterator] 를 key로 가지고 있는 property가 있어야한다.
- [Symbol.iterator] property의 value는 특정한 객체를 반환하는 함수이며, 이 함수에서 반환하는 객체는 Iterator 이다.
- Iterable Protocol은 반복 가능한 객체를 정의하는 규약이다.
- Iterable Protocol을 충족시키기 위해서는 객체는 [Symbol.iterator] 프로퍼티를 가지고 있어야 하며 이 프로퍼티의 값은 “Iterator 객체를 반환하는 함수"이다.
2. Iterator protocol
Iterator protocol은 특정한 값들의 순서를 만드는 표준 방법이다. 자바스크립트에서 객체가 특정 조건을 만족한다면 해당 객체는 iterator라고 할 수 있다.
iterator가 되기 위한 조건
- next 메소드를 가지고 있어야 한다.
- next 메소드는 done 과 value 두가지 프로퍼티를 가진 객체를 반환한다.
- done 프로퍼티는 boolean이며, 순회할 값이 남아있는지 여부를 표현한다.
a. done이 true일 경우, 모든 값들을 순회했다고 판단한다.
b. done이 false일 경우, 순회할 값이 남아있다고 판단한다. - value 프로퍼티는 순회 안에서 현재 반환할 값을 의미한다. done이 true일 경우 생략 가능하다.
const arr = ['a', 'b', 'c', 'd', 'e'];
const arrIter = arr[Symbol.iterator]();
console.log(arrIter.next().value); // a
console.log(arrIter.next().value); // b
console.log(arrIter.next().value); // c
console.log(arrIter.next().value); // d
console.log(arrIter.next().value); // e
console.log(arrIter.next().done); // true
// -----
const iterable = {
[Symbol.iterator]:() => {
let count = 0;
return {
next:() => {
return {
done: count > 3,
value: count++
}
}
}
}
}
// ------
function idMaker(){
let id = 0;
return {
next: function(){
return {value: id++, done: false};
}
};
}
var it = idMaker();
console.log(it.next().value); // '0'
console.log(it.next().value); // '1'
console.log(it.next().value); // '2'
- 참고자료
3. Generator Function & Genenrator
Iterator를 개발자가 직접 정의하는 것은 굉장히 유용하게 사용될 수 있다. 하지만 next method를 정의하고 그 안에서 value와 done property를 조작해서 매번 리턴해주는 것은 꽤나 번거롭고, 많은 주의를 기울여야 하는 일이다. 따라서 자바스크립트에서는 편리하게 Iterator 객체를 만들 수 있는 방법을 제공해준다.
자바스크립트에는 Generator Function이란 것이 존재한다. 이 함수는 Iterator의 일종인 Generator 객체를 리턴하는 함수다. 이 함수를 정의하기 위해서는 function* 키워드를 활용해야 한다.
// generator function
function* generatorFunction(i) {
yield i;
yield i + 10;
}
// return generator
const gen = generatorFunction(10);
// generator === interator, 따라서 next method를 호출할 수 있다.
console.log(gen.next().value);
// expected output: 10
console.log(gen.next().value);
// expected output: 20
- generator의 활용 예시
// generator 없이 구현
function idMaker(){
let id = 0;
return {
next: function(){
return {value: id++, done: false};
}
};
}
// generator를 활용한 구현
function* idMaker(){
let id = 0;
while(true) {
yield id++
}
}
it.next() // 0
it.next() // 1
it.next() // 2
it.next() // 3
// generator 없이 구현
const iterable = {
[Symbol.iterator]:() => {
let count = 0;
return {
next:() => {
return {
done: count > 3,
value: count++
}
}
}
}
}
// generator를 사용해 구현
const iterable = {
*[Symbol.iterator]() {
for(let i = 0; i < 4; i++){
yield i
}
}
}
- Generator 함수의 가장 큰 특징은 함수를 중간에 멈출 수 있다는 것
일반적인 함수는 호출 시 함수 안의 모든 코드를 일괄적으로 실행하고 종료되지만, Generator 함수의 경우에는 Generator의 next 메소드가 호출될 때 마다 yield 키워드를 만날때 까지만 실행되고, 그 이후엔 함수의 실행을 멈춘 채 대기한다.
함수를 멈출 수 있다는 특징은 다양한 방식으로 활용할 수 있다.
Ex) Redux-Saga와 같은 특정 라이브러리는 Generator 함수를 이용해 함수를 멈추는 테크닉을 활용한다.
function* generator(){
console.log("first")
yield 1
console.log("second")
yield 2
console.log("third")
yield 3
}
const iter = generator();
iter.next();
iter.next();
iter.next();
또한 generator의 next method를 호출하면서 인자를 전달 할 수도 있다.
- generator 함수는 next 메서드가 호출되면 yield를 만날때까지 실행된 후, yield에 멈춘다.
- 이후에 next 메서드를 호출하면서 전달한 인자는 현재 위치한 yield에 할당되게 된다.
- 그 이후에 다시 함수를 이어서 실행하고 yield를 만나면 멈추며 동일한 과정이 반복
function* generator(){
console.log("init")
const foo = yield 1
console.log("foo", foo)
const bar = yield 2
console.log("bar", bar)
const baz = yield 3
}
const iter = generator();
iter.next("Hello");
// 'init'
// { value: 1, done: false }
iter.next("Middle");
// 'foo' 'Middle'
// { value: 2, done: false }
iter.next("Bye");
// {'bar' 'Bye'}
// { value: 3, done: false }
- 참고자료
'Language > JavaScript' 카테고리의 다른 글
Promise & Async Await (0) | 2022.11.10 |
---|---|
[JavaScript] 비동기를 구현하는 방법 (Event loop & Callback) (0) | 2022.11.09 |
비동기에 대해서 (0) | 2022.11.08 |
Javascript ES6 전체적으로 살펴보기 (0) | 2022.06.27 |
[JavaScript] 유사 배열 객체(Array-like objects) (0) | 2022.03.23 |