import "./styles.css";
const cart = [
{ name: "사과", price: 3000, quantity: 30 },
{ name: "수박", price: 10000, quantity: 20 },
{ name: "복숭아", price: 5000, quantity: 40 }
];
const list = () => {
let html = "<ul>";
let totalCount = 0;
let totalPrice = 0;
for (let i = 0; i < cart.length; i++) {
html += "<li>";
html += `<h2>${cart[i].name}</h2>`;
html += `<div>가격 : ${cart[i].price}원</div>`;
html += `<div>수량 : ${cart[i].quantity}상자</div>`;
html += "</li>";
totalCount += cart[i].quantity;
totalPrice += cart[i].price * cart[i].quantity;
}
html += "</ul>";
html += `<h2>전체 수량: ${totalCount}상자</h2>`;
html += `<h2>전체 가격: ${totalPrice}원</h2>`;
return `
${html}
`;
};
document.getElementById("app").innerHTML = `
<h1>용기네 과일 가게</h1>
<div>
${list()}
</div>
`;
위의 코드는 for loop 안에 너무 많은 관심사가 겹쳐져 있다. 이를 심플하게 3개의 for문으로 먼저 분리해보자.
import "./styles.css";
import * as C from "./main";
const cart = [
{ name: "사과", price: 3000, quantity: 30 },
{ name: "수박", price: 10000, quantity: 20 },
{ name: "복숭아", price: 5000, quantity: 40 }
];
const list = () => {
let html = "<ul>";
for (let i = 0; i < cart.length; i++) {
html += "<li>";
html += `<h2>${cart[i].name}</h2>`;
html += `<div>가격 : ${cart[i].price}원</div>`;
html += `<div>수량 : ${cart[i].quantity}상자</div>`;
html += "</li>";
}
html += "</ul>";
let totalCount = 0;
for (let i = 0; i < cart.length; i++) {
totalCount += cart[i].quantity;
}
html += `<h2>전체 수량: ${totalCount}상자</h2>`;
let totalPrice = 0;
for (let i = 0; i < cart.length; i++) {
totalPrice += cart[i].price * cart[i].quantity;
}
html += `<h2>전체 가격: ${totalPrice}원</h2>`;
return `
${html}
`;
};
document.getElementById("app").innerHTML = `
<h1>용기네 과일 가게</h1>
<div>
${list()}
</div>
`;
하지만 여전히 문제가 있다. 일단 문제는 제쳐두고 여기에 품절 처리를 하는 로직만 추가해보자
import "./styles.css";
import * as C from "./main";
const cart = [
{ name: "사과", price: 3000, quantity: 30, outOfStock: false },
{ name: "수박", price: 10000, quantity: 20, outOfStock: true },
{ name: "복숭아", price: 5000, quantity: 40, outOfStock: false }
];
const list = () => {
let html = "<ul>";
for (let i = 0; i < cart.length; i++) {
if (cart[i].outOfStock === false) {
html += "<li>";
html += `<h2>${cart[i].name}</h2>`;
html += `<div>가격 : ${cart[i].price}원</div>`;
html += `<div>수량 : ${cart[i].quantity}상자</div>`;
html += "</li>";
} else {
html += "<li class='gray'>";
html += `<h2>${cart[i].name} (품절)</h2>`;
html += `<div class='strike'>가격 : ${cart[i].price}원</div>`;
html += `<div class='strike'>수량 : ${cart[i].quantity}상자</div>`;
html += "</li>";
}
}
html += "</ul>";
let totalCount = 0;
for (let i = 0; i < cart.length; i++) {
if (cart[i].outOfStock === false) {
totalCount += cart[i].quantity;
}
}
html += `<h2>전체 수량: ${totalCount}상자</h2>`;
let totalPrice = 0;
for (let i = 0; i < cart.length; i++) {
if (cart[i].outOfStock === false) {
totalPrice += cart[i].price * cart[i].quantity;
}
}
html += `<h2>전체 가격: ${totalPrice}원</h2>`;
return `
${html}
`;
};
document.getElementById("app").innerHTML = `
<h1>용기네 과일 가게</h1>
<div>
${list()}
</div>
`;
여기까지 명령형 프로그래밍 방식을 써서 구현을 해봤는데, 이걸 함수형으로 커스텀해보자. 그리고 이 때 사용할 키워드는 고차 함수
이다.
export const map = <A, B>(array: Array<A>, f: (a:A) => B): Array<B> => {
const result: Array<B> = [];
for( const value of array) {
result.push(f(value));
}
return result;
}
type MapType<A,B> = (xs: Array<A>, f: (x:A) => B) => Array<B>;
type MapType1 = MapType<number, string>;
const map: MapType1 = (array, f) => {
const result = [];
for( const value of array) {
result.push(f(value));
}
return result;
}
const arr = [1,2,3,4,5];
console.log(map(arr, (el) => el+ ""));
type Compose<A, B, C> = (g: (y:B) => C, f: (x:A) =>B) => (a:A) =>C;
type Compose1 = Compose<string, number, boolean>;
1) 장바구니를 그려야 한다.
2) 전체 가격과 전체 수량도 화면에 그려야 한다.
3) 재고 없는 상품의 처리
: 작은 단위의 순수 함수들을 레고 블록처럼 조립해서 큰 단위의 프로그램을 만들어보자.
아이템 목록 화면
전체 수량 표시
전체 가격 표시
사실 리액트를 써봤다면 위의 코드 구조가 좀 더 익숙하게 다가올 것이라고 생각된다. 이렇게 본래 명령형 프로그래밍으로 만든 기능을 -> 함수형 프로그래밍으로 리팩토링 해봤다. 컴퓨터에 명령을 내리는 듯한 방식이 아니라 인간의 발상을 옮겨놓은 듯한 코딩이 포인트라고 하는데, 아직은 확 와닿지는 않는다. 좀더 살펴보면서 아이디어를 얻는 방향으로 공부해보자.
: 사람이 사고하는 방식과 코드를 유사하게 만들자..(?)
: forEach는 return 값이 void이다(보통). 따라서,
: 시간복잡도 측면의 효율성 vs 인간의 사고 방향과 유사한 코드 작성(직관적인 코드)
: for 문 vs map & flatMap (or flat() )
** 참고로 flat() 은 cloneDeep처럼 재귀함수 형태로 돼있기 때문에 모든 배열 depth를 flat하게 하고자 하면 flat(Infinity);
이렇게 써주면된다(파라미터가 depth이다 flat(depth)
).