Total
Search
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
◦
전개 연산자
◦
구조 분해
◦
나머지 연산자
예시