이번에는 HTML을 구성해서 화면에 출력을 해보자. 일단 아래와 같이 함수가 구성된 상태에서 진행을 해보자.
<script>
const products = [
{ name: '반팔티', price: 15000, quantity: 1, is_selected: true },
{ name: '긴팔티', price: 20000, quantity: 2, is_selected: false },
{ name: '핸드폰케이스', price: 15000, quantity: 3, is_selected: true },
{ name: '후드티', price: 30000, quantity: 4, is_selected: false },
{ name: '바지', price: 25000, quantity: 5, is_selected: false }
];
const add = (a, b) => a + b;
const sum = curry((f, iter) => go(
iter,
map(f),
reduce(add)));
const total_quantity = sum(p => p.quantity);
const total_price = sum(p => p.price * p.quantity)
</script>
간단한 뼈대를 먼저 만들어보자. 아래결과와 같은 식으로 나온다고 생각해보자.
(template literal을(` `)을 사용했다.)
document.querySelector('#cart').innerHTML = `
<table>
<tr>
<th>상품 이름</th>
<th>가격</th>
<th>수량</th>
<th>총 가격</th>
</tr>
<tr>
<td>반팔티</td>
<td>10000</td>
<td><input type="number" value='3'></td>
<td>30000</td>
</tr>
<tr>
<td>반팔티</td>
<td>10000</td>
<td><input type="number" value='3'></td>
<td>30000</td>
</tr>
<tr>
<td colspan="2">합계</td>
<td>6</td>
<td>60000</td>
</tr>
</table >
`;
</script>
우선 총 가격과 총 수량은 이미 함수로 만들어 놓았다.
const total_quantity = sum(p => p.quantity);
const total_price = sum(p => p.price * p.quantity)
수량과 가격을 전달하면서 아래와 같이 넣어주자. 그러면 총 수량과 총가격을 가지고 있는 상품만큼이 출력된다.
<tr>
<td colspan="2">합계</td>
<td>${total_quantity(products)}</td>
<td>${total_price(products)}</td>
</tr>
반복한 products의 갯수만큼 반복하면서 상품을 출력해본다. go함수를 사용하면서 각각의 products에 해당하는 html string을 리턴하면 되기 때문에 map을 사용하면 된다. 각각의 product의 하나에 해당하는 html문자열을 리턴하는 것이다. product를 받아서 태그들을 template literal을 사용해서 아래와 같이 나타낸다.
<table>
<tr>
<th>상품 이름</th>
<th>가격</th>
<th>수량</th>
<th>총 가격</th>
</tr>
${go(products, map(p => `
<tr>
</tr>
`)
)}
잘라낸 것들은 아래와 같이 p.name p.price 등등을 넣어서 작성해준다. 하지만 이렇게 해주게 되면 아래와 같이 뭔가 이상하게 ,,,이 나타난다.
<table>
<tr>
<th>상품 이름</th>
<th>가격</th>
<th>수량</th>
<th>총 가격</th>
</tr>
${go(products, map(p => `
<tr>
<td>${p.name}</td>
<td>${p.price}</td>
<td><input type="number" value='${p.quantity}'></td>
<td>${p.price * p.quantity}</td>
</tr>
`)
)}
<tr>
<td colspan="2">합계</td>
<td>${total_quantity(products)}</td>
<td>${total_price(products)}</td>
</tr>
</table >
`;
,,,,이 생긴 이유는 map함수가 array를 리턴했기 때문이다.
${go(products,
map(p => `
<tr>
<td>${p.name}</td>
<td>${p.price}</td>
<td><input type="number" value='${p.quantity}'></td>
<td>${p.price * p.quantity}</td>
</tr>
`)
그래서 밑에서 문자열 더하기를 통해서 array가 아닌 하나의 값으로 만들어 주면 되는데 reduce를 해주고 문자열 더하기 (add)를 해준다. log를 출력해서 확인해보면 아래와 같다.
${go(products,
map(p => `
<tr>
<td>${p.name}</td>
<td>${p.price}</td>
<td><input type="number" value='${p.quantity}'></td>
<td>${p.price * p.quantity}</td>
</tr>
`),
reduce(add),
log
원래는 아래와 같이 되어있었을 것이다.
${go(products,
map(p => `
<tr>
<td>${p.name}</td>
<td>${p.price}</td>
<td><input type="number" value='${p.quantity}'></td>
<td>${p.price * p.quantity}</td>
</tr>
`),
log
즉 문자열이 배열에 들어있던 상태에서 reduce를 통해서 모두 다 하나의 문자열로 더해주게 되는것이다. 더해진 html문자열을 log를 빼고 치환을 해주면 아래와 같이 원하는 결과가 나온다.
${go(products,
map(p => `
<tr>
<td>${p.name}</td>
<td>${p.price}</td>
<td><input type="number" value='${p.quantity}'></td>
<td>${p.price * p.quantity}</td>
</tr>
`),
reduce(add))}
total_quantity를 만들 때 sum함수를 보면 pipe라인으로 구성이 되어있는데( map(f) reduce(add) )
const sum = curry((f, iter) => go(
iter,
map(f),
reduce(add)));
go 함수도 같은형식이다. (map => reduce)
${go(products,
map(p => `
<tr>
<td>${p.name}</td>
<td>${p.price}</td>
<td><input type="number" value='${p.quantity}'></td>
<td>${p.price * p.quantity}</td>
</tr>
`),
reduce(add))}
즉 sum함수는 map함수에 적용될 f함수가 리턴하는 값들을 다 add로 축약해주는 함수이기 때문에 go에서도 쓸 수 있다.
${go(products,
sum(p => `
<tr>
<td>${p.name}</td>
<td>${p.price}</td>
<td><input type="number" value='${p.quantity}'></td>
<td>${p.price * p.quantity}</td>
</tr>
`))}
이런식으로 함수형 프로그래밍에서는 다형성이 굉장히 높다. 함수 하나가 html을 만들기도 하고 가격과 수량을 곱한값을 더해주기도 하고 수령을 더해주기도 하므로 여러 데이터 구성에서도 쓰일 수가 있다.
마지막으로 코드상으로 선택된 상품과 선택되지 않은 상품들을 골라내는 화면을 나타내보자. 선택된 상품은 반팔티와 핸드폰 케이스로 구성되어 있다.
const products = [
{ name: '반팔티', price: 15000, quantity: 1, is_selected: true },
{ name: '긴팔티', price: 20000, quantity: 2, is_selected: false },
{ name: '핸드폰케이스', price: 15000, quantity: 3, is_selected: true },
{ name: '후드티', price: 30000, quantity: 4, is_selected: false },
{ name: '바지', price: 25000, quantity: 5, is_selected: false }
];
선택되었는지 여부를 나타내어 보자. Html로 표현하고 input 태그를 쓰고 checkbox를 쓰면서 p.is_selected가 true이면 checked를 넣고 아니면 빈 문자열을 넣는다.
그리고 선택된 상품에 대한 수량과 가격을 넣을려면 밑에 products자리에 평가되는 것들만 합산을 할 것이므로 해당부분에 filter를 해준다.
document.querySelector('#cart').innerHTML = `
<table>
<tr>
<th>상품 이름</th>
<th>가격</th>
<th>수량</th>
<th>총 가격</th>
</tr>
${go(products,
sum(p => `
<tr>
// 바뀐 거
<td><input type="checkbox" ${p.is_selected ? 'checked' : ''}></td>
<td>${p.name}</td>
<td>${p.price}</td>
<td><input type="number" value='${p.quantity}'></td>
<td>${p.price * p.quantity}</td>
</tr>
`))}
<tr>
<td colspan="2">합계</td>
// 바뀐 거
<td>${total_quantity(filter(p => p.is_selected, products))}</td>
<td>${total_price(filter(p => p.is_selected, products))}</td>
</tr>
</table >
`;
그러면 선택된 수량 4개와 선택된 총 가격이 나타난다.
지금까지 함수형 프로그래밍으로 html을 간단하게 만들어 보았다.
<출처 : 유인동 함수형 프로그래밍과 JavaScript ES6+>
https://www.inflearn.com/course/functional-es6/dashboard
함수형 프로그래밍과 JavaScript ES6+ - 인프런 | 강의
ES6+와 함수형 프로그래밍을 배울 수 있는 강의입니다. 이 강좌에서는 ES6+의 이터러블/이터레이터/제너레이터 프로토콜을 상세히 다루고 응용합니다. 이터러블을 기반으로한 함수형 프로그래밍,
www.inflearn.com
'JavaScript > 함수형 프로그래밍과 JavaScript ES6+' 카테고리의 다른 글
range와 느긋한 L.range 테스트 (0) | 2021.08.20 |
---|---|
range와 느긋한 range(지연성ⅰ) (0) | 2021.08.20 |
장바구니 예제(총 수량, 총 가격) (0) | 2021.08.19 |
함수 조합으로 함수 만들기 (0) | 2021.08.19 |
go + curry를 사용하여 더 읽기 좋은 코드로 만들기 (0) | 2021.08.19 |