일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- nextjs사용법
- 리스트 렌더링
- SCSS forward
- SCSS extend
- flex
- postcss
- SCSS use
- vue 이벤트 수신
- intersection opserver
- 프로그래머스 프론트엔드 데브코스
- KDT 프로그래머스 데브코스 프론트엔드
- 폼 입력 바인딩
- 프로그래머스 데브코스
- netlify redirect
- SCSS import
- 프로그래머스 데브코스 프론트엔드
- 리액트
- Vue
- react next
- git 같은계정 다른 컴퓨터
- 고양이 사진 검색기
- 이벤트 수식어
- vuex map
- 쌓임맥락
- KDT 프로그래머스
- vue mixin
- 프로그래머스 K_Digital Training
- 다른컴퓨터에서 git사용
- Spacer
- vue 지역 컴포넌트
- Today
- Total
혼자 적어보는 노트
프로그래머스 데브코스 TIL - Day 8 본문
✅ 학습 목차
- [Day 8] JavaScript 주요 문법 (8)
- 함수형 프로그래밍과 ES6+ (2)
✅ 새롭게 학습한 부분
- DOM
- Virtual DOM
- 함수형 프로그래밍 장바구니 예제
- 제너레이터:이터레이터 프로토콜의 지연 평가
DOM(Document Object Model)
웹페이지의 구성 요소를 제어하기 위해 문서의 구성요소들을 객체로 구조화하여 나타낸 모델
viortual DOM은 어떤 문제를 해결하기 위해 등장 했을까?
- DOM에 변화가 가해진다면 렌더트리를 기준으로 레이아웃을 배치하고 그리는 작업을 다시 하게된다.
- 즉, DOM을 반복적으로 조작했을 때 렌더링을 자주 하게되며 시간을 소모하게 된다.
Virtual DOM
- DOM을 추상화시킨 자바스크립트 객체를 의미한다.
- 직접 돔을 수정하지 않고 업데이트 된 부분을 모아서 실제 DOM과 변경된 Virtual DOm의 차이를 비교한 후
변경된 부분만 실제 DOM에 반영하는 방식.
Virtual DOM이 무조건 빠를까?
- DOM의 가상의 복사본인 virtualDOM을 생성하는 것 또한 메모리를 차지하는 부분이기 때문에
메모리 사용이 늘어난다.
- 동시에 변경되는 것에 한해서만 렌더링이 1번 진행되기 때문에 반복적인 움직임이 있을 경우
똑같이 최적화를 해주어야 한다.
+ createDocumentFragment
DocumentFragment는 기본적으로 DOM과 동일하게 동작하지만,
HTML의 DOM 트리에는 영향을 주지 않으며, 메모리에서만 정의된다.
다른 노드를 담는 임시 컨테이너와 같은 역할을 하는 노드
go, pipe, map, reduce를 사용하여
총 수량과 총 가격 구하기
(* map,reduce에는 curry가 감싸져있다.)
const go = (...args) => reduce((a, f) => f(a), args);
const pipe = (...fs) => (a) =>go(a, ...fs);
const fruits = [
{ name: "사과", price: 1000, quantity: 1 },
{ name: "오렌지", price: 2000, quantity: 2 },
{ name: "포도", price: 3000, quantity: 3 },
{ name: "파인애플", price: 5000, quantity: 4 },
{ name: "배", price: 1500, quantity: 5 },
];
const tatal_quantity = (fruits) =>
go(
fruits,
map((item) => item.quantity),
reduce((a, b) => a + b),
console.log
);
const tatal_quantity_pipe = pipe(
map((item) => item.quantity),
reduce((a, b) => a + b),
console.log
);
tatal_quantity(fruits); // 15
tatal_quantity_pipe(fruits); // 15
한번 더 추상화 시키기
const add = (a, b) => a + b;
const sum = (f, iter) => go(iter, map(f), reduce(add));
const tatal_quantity_pipe = (fruits) => sum((item) => item.quantity * item.price, fruits);
console.log(tatal_quantity_pipe(fruits)); // 41500
curry로 감싸기
const curry = (f) =>(a, ..._) => _.length ? f(a, ..._) : (..._) => f(a, ..._);
const add = (a, b) => a + b;
const sum = curry((f, iter) => go(iter, map(f), reduce(add)));
const tatal_quantity_pipe = sum((item) => item.quantity * item.price); // 코드 간소화 완료
console.log(tatal_quantity_pipe(fruits)); // 41500
curry로 함수를 감싸서 코드를 간소화 시킬 수 있다.
다형성을 이용하여 table로 결과 출력하기
const fruits = [
{ name: "사과", price: 1000, quantity: 1 },
{ name: "오렌지", price: 2000, quantity: 2 },
{ name: "포도", price: 3000, quantity: 3 },
{ name: "파인애플", price: 5000, quantity: 4 },
{ name: "배", price: 1500, quantity: 5 },
];
const add = (a, b) => a + b;
const sum = curry((f, iter) => go(iter, map(f), reduce(add)));
const tatal_quantity = sum((item) => item.quantity);
const tatal_price = sum((item) => item.quantity * item.price);
document.querySelector("#cart").innerHTML = `
<table>
<tr>
<td>상품이름<td>
<td>가격<td>
<td>수량<td>
<td>총가격<td>
</tr>
${go(
fruits,
sum(
(item) => `
<tr>
<td>${item.name}<td>
<td>${item.price}<td>
<td>${item.quantity}<td>
<td>${item.price * item.quantity}<td>
</tr>
`
)
)}
<tr>
<td>합계<td>
<td><td>
<td>${tatal_quantity(fruits)}<td>
<td>${tatal_price(fruits)}<td>
</tr>
</table>
`;
sum으로 값을 만들어 낼 수도 있지만 태그들을 반환할 수도 있다.
지연 평가(Laze Evaluation)
- 지연평가 = 제때 계산법 = 느긋한 계산법
- 제너레이터/이터레이터 프로토콜을 기반으로 구현
- 제너레이터로 생성한 이터레이터를 만나서 값을 꺼낼 필요가 생길 때 까지 평가를 미루는 기법.
range 함수 만들기
0부터 n까지의 값을 담는 배열을 만드는 range 함수와
generator를 사용하여 만든 느긋한 L.range를 비교 해보기
const range = (l) => {
const res = [];
let i = -1;
while (++i < l) {
res.push(i);
}
return res;
};
const list = range(5);
console.log(list); // [0, 1, 2, 3, 4] *이미 평가가되어 값이 만들어짐
console.log(reduce((a, b) => a + b, list)); // 10
const L = {};
L.range = function* (l) {
let i = -1;
while (++i < l) {
yield i;
}
};
const list2 = L.range(5);
console.log(list2); // L.range {<suspended>}
// *아직 순회가 돌지 않은 상태이고
// L.range내부의 함수는 이터레이터를 순회할 때 실행된다.
console.log(reduce((a, b) => a + b, list2)); // 10
range와 L.range의 reduce로 반환된 값은 같지만
range의 list는 값이 만들어진 상태이고 (reduce에서 iterator로 변환)
generator로 만든 iterator인 L.range는 순회가 돌기 전까지는 함수 내부가 실행되지 않는다.
효율성 측면에서는 L.range가 더 좋다.
take함수로 알아보는 효율성
주어진 값만큼 잘라서 반환하는 take함수로 효율성을 알아볼 수 있다.
const take = (l, iter) => {
let res = [];
for (const a of iter) {
res.push(a);
if (res.length == l) return res;
}
return res;
};
console.time("");
console.log(take(5, range(9999999))); // 196.229ms
console.timeEnd("");
console.time("");
console.log(take(5, L.range(9999999))); // 0.075ms
console.timeEnd("");
range함수는 9999999의 값을 가지고 평가된 배열을 만들고 take를 이용해서 5개를 자르게 된다.
하지만 L.range 함수는 순회를 돌 때 실행되기 때문에 5번만 순회를 하게된다.
무한대의 값인 Infinity값을 넣더라도 take에 작성한 값만큼만 순회를 한다.
L.map / L.filter
L.map = function* (f, iter) {
for (const a of iter) yield f(a);
};
const it = L.map((a) => a + 1, [10, 20, 30]); // 아직 평가되지 않음
console.log(it.next()); // {value: 11, done: false}
console.log(it.next()); // {value: 21, done: false}
console.log(it.next()); // {value: 31, done: false}
L.filter = function* (f, iter) {
for (const a of iter) if (f(a)) yield a;
};
const it2 = L.filter((a) => a > 10, [10, 20, 30]); // 아직 평가되지 않음
console.log([...it2]); // [20, 30]
L.map과 L.filter 또한 값을 꺼낼 필요가 있을 때 내부의 함수를 실행하게 된다.
✍ 느낀 점
드디어 알고리즘 파트가 오늘로서 끝났다..
아직 높은 레벨의 문제들은 풀질 못해서 차근차근 낮은단계부터 꾸준하게 문제를 풀어보며 익힐 예정이다..
함수형 프로그래밍 파트에서 지연평가 기법을 따라서 치다보니 이해가 약간은 된 듯 했다.
이전엔 generator는 왜 쓸까? 했는데 이런 효율성 때문에 사용할 수도 있겠구나~하는 이해가 생겼다.
한 줄씩 평가하고 넘어가는 방식이 아닌 새로운 방식의 평가 순서도 아주 인상 깊었다.😲👍
하지만 어떤 식으로 응용이 가능할 지 감이 잘 잡히지 않는다.
보는 것과 활용하는 것은 다르기 때문에 함수형 사고를 조금씩 더 키워 나가야겠다!
'스터디' 카테고리의 다른 글
프로그래머스 데브코스 TIL - Day 10 (0) | 2022.04.03 |
---|---|
프로그래머스 데브코스 TIL - Day 9 (0) | 2022.04.01 |
프로그래머스 데브코스 TIL - Day 7 (0) | 2022.03.29 |
프로그래머스 데브코스 TIL - Day 6 (0) | 2022.03.28 |
프로그래머스 데브코스 TIL - 1주차 보충 (0) | 2022.03.26 |