728x90
map
// map (고차함수)
// 함수에서는 처리한 결과값을 리턴하게 된다
const map = (f, iter) => {
let res = [];
for (const a of iter) {
res.push(f(a));
}
return res;
};
// 예제 1
let names = [];
for (const p of products) {
names.push(p.name);
}
console.log(names);
// map을 이용해서 다시 작성한 예제 1
console.log(map(p => p.name, products));
// 예제 2
let prices = [];
for (const p of products) {
prices.push(p.price);
}
console.log(prices);
// map을 이용해서 다시 작성한 예제 2
console.log(map(p => p.price, products));
map의 다형성 1
// map의 다형성 1
// 이터러블 프로토콜을 따르고 있기 때문에 다형성이 높다
console.log([1, 2, 3].map(a => a + 1));
// document.querySelectorAll는 배열을 상속받은 객체가 아니라서 map 함수를 사용할 수가 없다
// console.log(document.querySelectorAll('*').map(el => el.nodeName));
console.log(document.querySelectorAll('*'));
// 앞에서 만든 map 함수가 작동하는 이유는 iterable 순회가 가능한 for..of 문으로 작성했기 때문이다
console.log(map(el => el.nodeName, document.querySelectorAll('*')));
// const it = document.querySelectorAll('*')[Symbol.iterator]();
// console.log(it.next());
// console.log(it.next());
// console.log(it.next());
// console.log(it.next());
// console.log(it.next());
// console.log(it.next());
// console.log(it.next());
function *gen() {
yield 2;
if (false) yield 3;
yield 4;
}
// 제너레이터 함수들의 결과물들도 map을 사용할 수 있게 됨
console.log(map(a => a * a, gen()));
map의 다형성 2
// map의 다형성 2
let m = new Map();
m.set('a', 10);
m.set('b', 20);
console.log(m);
console.log((map(([k, a]) => [k, a * 2], m))); // function, iterable, k = key, a = value
console.log(new Map(map(([k, a]) => [k, a * 2], m)));
위에서 만든 map 함수를 사용해서 새로운 Map 객체를 생성할 수 있다.
filter
// filter
const filter = (f, iter) => {
let res = [];
for(const a of iter) {
if(f(a)) res.push(a);
}
return res;
};
// 예제 1
let under20000 = [];
for(const p of products) {
if(p.price < 20000) under20000.push(p);
}
console.log(...under20000);
// 예제 1 리팩토링
console.log(...filter(p => p.price < 20000, products));
// 예제 2
let over20000 = [];
for(const p of products) {
if(p.price >= 20000) over20000.push(p);
}
console.log(...over20000);
// 예제 2 리팩토링
console.log(...filter(p => p.price >= 20000, products));
// 다양한 활용 예시
console.log(filter(n => n % 2, [1, 2, 3, 4]));
console.log(filter(n => n % 2, function *() {
yield 1;
yield 2;
yield 3;
yield 4;
yield 5;
} ()));
reduce
// reduce : 값을 누적하면서 새로운 값을 반환하는 함수
const nums = [1, 2, 3, 4, 5];
let total = 0;
for (const n of nums) {
total = total + n;
}
console.log(total);
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 add = (a, b) => a + b;
console.log(reduce(add, 0, [1, 2, 3, 4, 5]));
// 15
console.log(add(add(add(add(add(0, 1), 2), 3), 4), 5));
// 15
// reduce 함수에 필요한 초기값인 acc를 입력하지 않아도 작동함
console.log(reduce(add, [1, 2, 3, 4, 5]));
// reduce 2
console.log(
reduce(
(total_price, product) => total_price + product.price,
0,
products));
map+filter+reduce 중첩 사용
const products = [
{ name: '반팔티', price: 15000 },
{ name: '긴팔티', price: 20000 },
{ name: '핸드폰케이스', price: 15000 },
{ name: '후드티', price: 30000 },
{ name: '바지', price: 25000 }
];
const add = (a, b) => a + b;
console.log(
reduce(
add,
map(p => p.price,
filter(p => p.price < 20000, products))));
console.log(
reduce(
add,
filter(n => n >= 20000,
map(p => p.price, products))));
확실히 코드가 간결해지고 깔끔해지는게 느껴진다.
반응형
'JavaScript > 함수형 프로그래밍과 JavaScript ES6+' 카테고리의 다른 글
제너레이터와 이터레이터 (0) | 2021.11.24 |
---|---|
ES6에서의 순회와 이터러블:이터레이터 프로토콜(2) (0) | 2021.11.04 |
ES6에서의 순회와 이터러블:이터레이터 프로토콜(1) (0) | 2021.11.03 |
함수형 자바스크립트 기본기 (0) | 2021.10.31 |
댓글