Search
🏛️

[FP & JS ES6+] 1. 이터러블, 이터레이터, 제너레이터

Tags
Javascript
Functional Programming
Study
Last edited time
2023/10/05 13:55
2 more properties
Search
[FP & JS ES6+] 6. 비동기: 동시성 프로그래밍 (3) - async/await, Q&A
Javascript
Functional Programming
Study
2023/10/06 14:19
[FP & JS ES6+] 6. 비동기: 동시성 프로그래밍 (3) - async/await, Q&A
Javascript
Functional Programming
Study
2023/10/06 14:19

1. 함수형 자바스크립트 기본기

평가
코드가 계산(Evaluation) 되어 값을 만드는 것
일급
값으로 다를 수 있음
변수에 담을 수 있음
함수의 인자나 결과로 사용될 수 있음
일급 함수
함수를 값으로 다를 수 있음
조합성과 추상화의 도구
고차 함수
함수를 값으로 다루는 함수
종류
함수를 인자로 받아서 실행하는 함수 (applicative programming)
const apply1 = f => f(1); const add2 = a => a + 2; // const apply2 = f => (a => a + 2)(1); console.log(apply1(add2)) // 3 console.log(apply1(a => a - 1)) // 0 const times = (f, n) => { let i = -1; while (++i < n) f(i) } times(console.log, 3); // 0, 1, 2 times(a => console.log(a + 10), 3); // 10, 11, 12
JavaScript
복사
함수를 만들어 리턴하는 함수 (클로저를 만들어 리턴하는 함수)
const addMaker = a => b => a + b; // b 이하 함수가 a를 기억하고 있음 (클로저) const add10 = addMaker(10) console.log(add10.toString()) // b => a + b console.log(add10(5)) //15
JavaScript
복사

2. 순회와 이터러블

2.1. 순회

순회
for i++
for of
set, map
for of로 순회가능
그러나 인덱스로 접근 불가
console.log('Set ------------') const set = new Set([1, 2, 3]); for (const a of set) console.log(a) // 1, 2, 3 console.log(set[0]) // undefined console.log('Map ------------') const map = new Map([['a', 1], ['b', 2], ['c', 3]]); for (const a of map) console.log(a) // [ 'a', 1 ], [ 'b', 2 ], [ 'c', 3 ] console.log(map[0]) // undefined
JavaScript
복사

2.2. 이터러블/이터레이터 프로토콜

Symbol.iterator
객체의 키로 사용 가능
배열에 Symbol.iterator 로 접근하면 함수가 출력됨
Symbol.iterator 를 null로 설정하면 순회 불가
const arr = [1, 2, 3]; console.log(arr[Symbol.iterator].toString()) // function values() { [native code] } arr[Symbol.iterator] = null; for (const a of arr) console.log(a) // TypeError: arr is not iterable
JavaScript
복사
이터러블
이터레이터를 리턴하는 [Symbol.iterator]()를 가진 값
array, set, map은 이터러블이라고 할 수 있음
이터레이터
{ value, done } 객체를 리턴하는 next()를 가진 값
이터러블/이터레이터 프로토콜
이터러블을 for … of, 전개 연산자 등의 문법과 함께 동작하도록 한 규약
const arr2 = [1,2,3] let iterator = arr2[Symbol.iterator](); // Object [Array Iterator] {} console.log(iterator) console.log(iterator.next()); // { value: 1, done: false } console.log(iterator.next()); // { value: 2, done: false } console.log(iterator.next()); // { value: 3, done: false } console.log(iterator.next()); // { value: undefined, done: true }
JavaScript
복사

2.3. 사용자 정의 이터러블

이터러블 프로토콜을 준수하여 사용자 정의 이터러블을 만들 수 있음
Symbol.iterator 키 추가
{ value, done } 객체를 리턴하는 next()를 가진 값
const iterable = { [Symbol.iterator]() { let i = 3; return { next() { return i == 0 ? {done: true} : {value: i--, done: false} } } } } let iterator = iterable[Symbol.iterator](); for (const a of iterable) { console.log(a) } console.log(iterator.next()) console.log(iterator.next()) console.log(iterator.next()) console.log(iterator.next())
JavaScript
복사
잘 구현된 이터러블은 이터레이터를 만들었을 때, 이터레이터를 진행하다가 순회할 수 도 있고, 이터레이터를 그대로 for문에 넣었을 때 정상동작해야함
이터레이터가 자기자신을 반환하는 Symbol.iterator 메서드를 가지고 있을 때 well-formed iterator 라고 할 수 있음
const arr2 = [1, 2, 3] for (const a of arr2) console.log(a) let iter2 = arr2[Symbol.iterator](); console.log(iter2.next()) // { value: 1, done: false } for (const a of iter2) console.log(a) // 2, 3 console.log(iter2[Symbol.iterator]() == iter2) // true
JavaScript
복사

2.4. well-formed iterator

조건
이터러블 (이터레이터를 리턴하는 [Symbol.iterator]()를 가진 값)으로도 순회 가능
이터레이터 ({ value, done } 객체를 리턴하는 next()를 가진 값) 으로도 순회 가능
이터레이터가 자기자신을 반환하는 [Symbol.iterator]() 를 갖고 있음
일정부분 이러테리터를 진행한 다음에도 순회가 가능
const iterable = { [Symbol.iterator]() { let i = 3; return { next() { return i == 0 ? {done: true} : {value: i--, done: false} }, [Symbol.iterator]() { return this; } } } } let iterator = iterable[Symbol.iterator](); iterator.next() for (const a of iterator) console.log(a) // 2, 1 for (const a of iterable) console.log(a) // 3, 2, 1 for (const a of iterable[Symbol.iterator]()) console.log(a) // 3, 2, 1
JavaScript
복사

2.5. 전개 연산자

전개 연산자도 이터러블 프로토콜을 따름
array, set, map 모두 전개연산자로 사용 가능
const a = [1, 2]; console.log(...a); // 1, 2 console.log([...a, ...[3, 4]]); // [1,2,3,4] a[Symbol.iterator] = null; console.log([...a, ...[3, 4]]); // TypeError: a is not iterable const set = new Set([1, 2, 3]); const map = new Map([['a', 1], ['b', 2], ['c', 3]]); console.log([...a, ...set, ...map]);
JavaScript
복사

3. 제너레이터와 이터레이터

3.1. 제너레이터/이터레이터

제너레이터
이터레이터이자 이터러블을 생성하는 함수
well-formed iterator를 Return하는 함수
return 값 설정 가능
done: true 일떄 return 되는 값
실행결과가 이터레이터이자 이터러블 → 순회 가능
return 값은 순회할때 평가되지 않음
function *gen() { yield 1; yield 2; yield 3; return 100; } let iter = gen(); console.log(iter.next()); // { value: 1, done: false } console.log(iter.next()); // { value: 2, done: false } console.log(iter.next()); // { value: 3, done: false } console.log(iter.next()); // { value: 100, done: true } console.log(iter[Symbol.iterator]() == iter) // true for (const a of gen()) { console.log(a) }
JavaScript
복사
제너레이터는 순회할 값을 문장으로 표현하는 것
문장을 통해 순회할 수 있는 값을 만들 수 있음
제너레이터를 통해서 어떠한 상태나 어떠한 값이든 순회할 수 있는 이터러블을 만들 수 있음
function *gen() { yield 1; if (false) yield 2; yield 3; } for (const a of gen()) { console.log(a) } // 1, 3
JavaScript
복사
예제

3.2. 제너레이터와 이터러블 프로토콜

다양한 이터러블 프로토콜에 제너레이터 활용 가능
for of
전개 연산자
구조 분해
나머지 연산자
예시