인프런 함수형 프로그래밍과 JavaScript ES6+ 강의 들으면서 정리하는 곳

<aside> 💡 평가 : 코드가 계산(Evaluation) 되어 값을 만드는 것

일급 : - 값으로 다룰 수 있다. - 변수에 담을 수 있다. - 함수의 인자로 사용될 수 있다. - 함수의 결과로 사용될 수 있다.

일급함수 : - 함수를 값으로 다룰 수 있다. - 조합성과 추상화의 도구

고차함수 : - 함수를 값으로 다루는 함수 고차함수 종류 두 가지 : - 함수를 인자로 받아서 실행하는 함수

const apply1 = f => f(1);
const add2 = a => a+2;
log(apply(add2)); 
결과 3

const times = (f,n) => {
	let i = -1;
	while(++i < n) f(i);
}

times(log, 3)
결과 0 1 2 

times(a => log(a+10), 3)
결과 10 11 12 
         - 함수를 만들어 리턴하는 함수 (클로저를 만들어 리턴하는 함수)
const addMaker = a => b => a + b;
const add10 = addMaker(10); 
log(add10);
결과 b => a + b;
log(add10(5))
결과 15

기존과 달라진 리스트 순회

for(const a of list) {
	console.log(a);
}

이걸 사용하면 Map Set도 순회 가능하다 

## 이터러블/이터레이터 프로토콜 
- 이터러블 : 이터레이터를 리턴하는 [Symbol.iterator]()를 가진 값 
- 이터레이터 : {value, done} 객체를 리턴하는 next()를 가진 값
- 이터러블/이터레이터 프로토콜 : 이터러블을 for...of, 전개 연산자 등과 함께 동작하도록 규약 

제너레이터 : 이터레이터이자 이터러블을 생성하는 함수

function *gen() {
	yield 1;
	yield 2;
	yield 3; 
}

let iter = gen();

log(iter[Symbol.iterator]() == iter);

log(iter.next());
log(iter.next());
log(iter.next());

for(const a of gen()) log(a);

자바스크립트에서는 어떠한 값이든 이터러블이면 순회할 수 있다. 제너레이터는 문장을 값으로 만들 수 있고 그 문장을 통해서 순회할 수 있는 값을 만들수 있기 때문에 자바스크립트에서는 제너레이터를 통해서 어떠한 상태나 값이든 순회할 수 있게 만들 수 있다.

제너레이터를 활용한 홀수찍기

function *infinity(i = 0) {
	while(true) yield i++;
}

function *limit(l,iter){
	for(const a of iter) {
		yield a;
		if(a == l) return;
	}
}

function *odds(l){
	for(const a of limit(l, infinity(1))) {
		if(a % 2) yield a; 
	}
}

for(const a of odds(40)) log(a);
const [a, b, ...c] = [1,2,3,4,5,6];
a => 1
b => 2 
c => [3,4,5,6]

함수형 map 함수

const map = (f, iter) => {
	let res = [];
	for(const a of iter) {
		res.push(f(a));
	}
	return res;
}

log(document.querySelectorAll(*).map(el => el.nodeName));
// doucument.querySelectorAll는 array를 상속받은게 아니라서 내부에 map함수가 구현이 
// 안되어있음 그래서 위처럼 하면 undefiend뜬다 하지만  

map(el => el.nodeName, document.querySelectAll(*))); 
// 이건 동작한다. 이거는 되는 이유가 document.querySelectAll(*) 이터러블 프로토콜을 
// 따르기 때문 

function *gen() {
	yield 2;
	if(false) yield 3;
	yield 4; 
}

log(map(a => a*a, gen()); // 4,16

let m = new Man();
m.set('a', 10);
m.set('b'',20);
log(new Map(map(([k,a]) => [k, a*2], m)));

함수형 filter 함수

const products = [
	{name : '반팔티', price: 15000},
	{name : '긴팔티', price: 20000},
	{name : '후드티', price: 25000},
	{name : '목티', price: 30000},
];
 

const filter = (f, iter) => {
	let res = [];
	for(const a of iter) {
		if(f(a)) res.push(a);
	}
	return res;
}

	log(...filter(p => p.price < 20000. products));

함수형 reduce함수

const products = [
	{name : '반팔티', price: 15000},
	{name : '긴팔티', price: 20000},
	{name : '후드티', price: 25000},
	{name : '목티', price: 30000},
];

const reduce  = (f, acc, iter) => {
	if(!iter) {
		iter = acc[Symbol.iterator]();
		acc = iter.next().value;
	}
	for(const a of iter) {
		acc = f(acc,a);
	}
	return acc;
}

log(reduce((total_price, product) => total_price + product.price, 0, products));

함수형 함수들 중첩 사용과 함수형 사고

const products = [
	{name : '반팔티', price: 15000},
	{name : '긴팔티', price: 20000},
	{name : '후드티', price: 25000},
	{name : '목티', price: 30000},
];

const add = (a,b) => a+b;

log(reduce(add, map(p => p.price, filter(p => p.price < 20000, products))));
// 코드가 복잡해 보이지만 오른쪽에서 왼쪽으로 읽어나가면 된다. 

log(reduce(add, filter(n => n < 20000, map(p => p.price, products))));
// 위에 쓴거랑 순서는 다르지만 값은 똑같다. 

// 이런 식으로 중첩 함수들을 구현 할 때는 왼쪽에서 부터 하나하나 생각해서 내가 기대하는
// 값의 모양을 만들어주는 함수를 써서 오른쪽에 구현해준다고 생각하면 될 듯 

</aside>