지연성을 가진 L.map을 구현해보자.
앞서 가졌던 map을 지연성을 가진 map으로 만들되, 제너레이터 이터레이터 프로토콜을 기반으로 구현해보는 L.map이 될 것이다.
L.map은 평가를미루는 성질을 가지고 평가 순서를 조금 달리 조작할 수 있는 준비가 되어있는 이터레이터를 반환하는 제너레이터 함수라고 볼 수 있다. 코드를 구현해보자.
단계적으로 구현해보자. L.map은 제너레이터 함수이고
<script>
L.map = function *() {
}
</script>
이터러블값만 받도록 한다. 그리고 내부에 있는 값을 순회를 하면서 yield를 통해서 해당하는 값을 그대로 꺼내는 것이다.
<script>
L.map = function *(iter) {
for (const a of iter) yield a;
}
</script>
아래와 같은 map함수가 있다 했을 때 L.map을 만들고 결과를 받아서 next를 하면 아래결과가 나온다.
<script>
L.map = function* (iter) {
for (const a of iter) yield a;
};
var it = L.map([1, 2, 3]);
log(it.next());
log(it.next());
log(it.next());
</script>
//{value: 1, done: false}
//done: false
//value: 1
//[[Prototype]]: Object
//{value: 2, done: false}
//done: false
//value: 2
//[[Prototype]]: Object
//{value: 3, done: false}
//done: false
//value: 3
//[[Prototype]]: Object
추가로 mapping할 함수를 받아주고 값마다 함수를 적용해준다.
L.map의 특징은 next를 통해서 평가한 만큼의 값만 얻어올 수 있다.
<script>
L.map = function* (f, iter) {
for (const a of iter) yield f(a);
};
var it = L.map(a => a + 10, [1, 2, 3]);
log(it.next());
log(it.next());
log(it.next());
</script>
//{value: 11, done: false}
//done: false
//value: 11
//[[Prototype]]: Object
//{value: 12, done: false}
//done: false
//value: 12
//[[Prototype]]: Object
//{value: 13, done: false}
//done: false
//value: 13
//[[Prototype]]: Object
그래서 spread operator를 통해서는 아래와 같은 결과를 만들 수도 있다.
[...it]
(3) [11, 12, 13]
L.map 자체에서는 새로운 array를 만들지 않고 값 하나하나 순회하면서 yield를 통해 함수가 적용된 값을 이터레이터에 next를 실행할 때마다 하나씩 전달하게 되고 그러한 준비가 되어있는 이터레이터 객체를 원하는 방법으로 평가할 수 있다. spread operator라든지 next를 사용해서 평가를 할 수 있는것이다.
[...it]
(3) [11, 12, 13]
[it.next().value]
[11]
지연성을 가진 L.filter를 구현해보자.
L.map과 거의 비슷한데 약간의 코드만 수정하면 된다. 아래와 같은 상태에서
<script>
L.filter = function* (f, iter) {
for (const a of iter) yield f(a);
};
</script>
이터레이터를 모두 순회하면서 yield한 값이 L.filter에 경우에는 f를 적용한 해당하는 값이 아니라 f를 적용해 봤을 때 true 평가되는 값이 떨어지면 그때만 a를 yield하는 식으로 구현을 한다.
<script>
L.filter = function* (f, iter) {
for (const a of iter) if (f(a)) yield a;
};
</script>
이제 L.filter에 값이 있고 a를 받아서 a % 2를 해주고 해당값에 next를 하게되면 아래와 같은 결과가 나온다.
1 3 false 식으로 한번씩 건너뛰게 된다. next를 할 때마다 yield를 하는데 yield가 총 4번이 되는 것이 아니라
원하는 상황에서만 yield가 되기 때문에 그 때만 해당하는 값이 떨어져서 next를 여러번 했을 때 done true가 되기 전까지 해당하는 값을 필터링을 해서 next했을 때 value가 꺼내지도록 구성이 되었다.
<script>
L.filter = function* (f, iter) {
for (const a of iter) if (f(a)) yield a;
};
var it = L.filter(a => a % 2, [1, 2, 3, 4]);
log(it.next())
log(it.next())
log(it.next())
</script>
<출처 : 유인동 함수형 프로그래밍과 JavaScript ES6+>
https://www.inflearn.com/course/functional-es6/dashboard
함수형 프로그래밍과 JavaScript ES6+ - 인프런 | 강의
ES6+와 함수형 프로그래밍을 배울 수 있는 강의입니다. 이 강좌에서는 ES6+의 이터러블/이터레이터/제너레이터 프로토콜을 상세히 다루고 응용합니다. 이터러블을 기반으로한 함수형 프로그래밍,
www.inflearn.com
'JavaScript > 함수형 프로그래밍과 JavaScript ES6+' 카테고리의 다른 글
결과를 만드는 함수 reduce, take (0) | 2021.08.24 |
---|---|
range, map, filter, take, reduce 중첩 사용(개발자도구로 순서확인) (0) | 2021.08.20 |
제너레이터 / 이터레이터 프로토콜로 구현하는 지연 평가 (0) | 2021.08.20 |
take 함수 (0) | 2021.08.20 |
range와 느긋한 L.range 테스트 (0) | 2021.08.20 |