프론트엔드/JS

[JavaScript] go, pipe로 읽기 좋은 코드 만들기

턴태 2023. 4. 27. 23:50

기존 함수의 문제

https://dev-scratch.tistory.com/150

 

[JavaScript] Map + Filter + Reduce 중첩 사용과 함수형 사고

Map, Filter, Reduce 중첩하여 사용 map, filter, reduce 함수를 커스텀으로 생성하고, 이를 중첩하여 사용해봄으로써 함수형 사고에 대해 배우고자 한다. 각각의 함수는 아래와 같이 작성할 수 있다. const m

dev-scratch.tistory.com

앞선 게시물에서 여러 개의 함수를 중첩하여 사용하다보니까 코드는 간결하지만 가독성이 그리 좋지 않았다. 그렇기에 이를 보완할 필요가 있어 보인다.

 

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

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;
};
const products = [
	{ name: '반팔티', price: 15000 },
    { name: '긴팔티', price: 20000 },
    { name: '핸드폰케이스', price: 15000 },
    { name: '후드티', price: 30000 },
    { name: '바지', price: 25000 },
];
const add = (a, b) => a + b;

reduce(add, map(p => p.price, filter(p => p.price < 20000, products))));

위 코드는 읽기 편한 코드가 아니기 때문에 가독성을 높일 필요가 있어 보인다.

 

Go 함수 만들기

const go = () => {};

go(
	0,
    a => a + 1,
    a => a + 10,
    a => a + 100,
    console.log(a));
);
// 111

위처럼 뼈대를 만들었을 때, 원하는 과정은 a의 값을 점점 업데이트하면서 111이라는 값을 얻고자 한다.

const go = (...args) => {};

일단 위처럼 수정하면, 함수 매개변수들을 받아 사용할 수 있다.

 

여기서 reduce를 안에 넣어 사용해볼 수 있다.

 

const go = (...args) => reduce((a, f) => f(a), args);

go(
	0,
    a => a + 1,
    a => a + 10,
    a => a + 100,
    console.log(a)
);

위처럼 작성하면 reduce함수에 내가 원하는 함수들을 인자로 넣어 값을 조금 더 가독성 있게 풀어낼 수 있다.

 

pipe 함수

go 함수는 함수들과 인자를 전달해 즉시 값을 계산해 전달한다. pipe 함수는 함수를 리턴하는 함수로, 함수들을 합성한다.

const pipe = () => () => {};

const f = pipe(
	a => a + 1,
    a => a + 10,
    a => a + 100);

이렇게 작성했을 때, f(0)을 호출해 앞선 결과와 똑같이 111을 리턴하는 함수를 만들 차례이다.

 

pipe 함수는 내부적으로 go를 사용하는 함수이다.

const pipe = (...fs) => (a) => go(a, ...fs);

이를 다음과 같이 불러와 사용한다.

const f = pipe(
	a => a + 1,
    a => a + 10,
    a => a + 100,
);

f(0);

즉, f에게 pipe 함수를 실행하면,

f = (a) => go(a, 
	a => a + 1,
    a => a + 10,
    a => a + 100,
);

와 같은 꼴이 되는 것이다.

 

여기서 기능을 추가해보자.

첫 번째 값이 여러 개의 인자를 받고자 할 때 아래와 같이 수정할 수 있다.

const pipe = (f, ...fs) => (...as) => go(f(...as), ...fs);

const f = pipe(
	(a, b) => a + b,
    a => a + 10,
    a => a + 100
);

f(0, 1);

즉 이는 아래와 같은 의미이다.

f = (...as) => go((a, b) => a + b, ...fs);