이번 시간에는 map, filter, reduce에 대해 알아보겠습니다.
➡️ map()
메서드는 배열 내의 모든 요소 각각에 대하여 주어진 함수를 호출한 결과를 모아 새로운 배열을 반환합니다.
map 함수를 직접 작성해보겠습니다.
const products = [
{name: '반팔티', price: 15000},
{name: '긴팔티', price: 20000},
{name: '핸드폰케이스', price: 15000},
{name: '후드티', price: 30000},
{name: '바지', price: 25000}
];
const map = (f, iter) => { // 이터러블 프로토콜을 따르는 인자를 받게 됩니다.
let res = [];
for (const a of iter) {
res.push(f(a)); // 함수에 위임을 하게 됩니다.
}
return res; // 결과를 리턴합니다.
};
이 map
함수를 이용해 products의 이름만 뽑아 보겠습니다.
map(p=>p.name, products)
이렇게 함수 부분에는 이름을 리턴해주는 함수를 전달하고, iter
에는 products
를 전달해줍니다.
➡️ map 함수는 이터러블 프로토콜을 따르기 때문에 다형성이 높습니다.
따라서 이터러블 프로토콜을 따르는 모든 것에 대해 map 함수를 사용할 수 있습니다.
function* gen() {
yield 2;
yield 3;
yield 4;
}
console.log(map(a => a * a, gen()));
이런식으로 제너레이터 함수의 결과값도 수집하여 제어할 수 있습니다.
➡️ 특정 데이터에서 조건에 따라서 필터링을 해주는 코드라고 말할 수 있습니다.
filter
함수를 직접 작성해보겠습니다.
const filter = (f, iter) => {
let res = [];
for (const a of iter) {
if (f(a)) res.push(a); // 보조 함수를 통해서 조건을 체크합니다.
}
return res;
};
filter
함수도 마찬가지로 역할을 보조 함수에 위임하여 구현됩니다. 또한, map
함수랑 동일하게 제너레이터 함수의 값을 다룰 수 있게 됩니다.
function* gen() {
yield 1;
yield 2;
yield 3;
yield 4;
yield 5;
}
console.log(filter(n => n % 2, gen()));
결과
(3) [1, 3, 5]
➡️ reduce() 메서드는 배열의 각 요소에 대해 주어진 리듀서(reducer) 함수를 실행하고, 하나의 결과값을 반환합니다. 즉, 이터러블 값을 하나의 값으로 축약해 나가는 함수라고 말할 수 있습니다.
리듀서 함수는 네 개의 인자를 가집니다.
예시를 통해 살펴보겠습니다!
const nums = [1, 2, 3, 4, 5];
const reduce = (f, acc, iter) => { // 보조 함수, 누적 값, 이터러블
if (!iter) {
iter = acc[Symbol.iterator](); // acc의 이터러블 값을 iter에 넣어줍니다.
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, nums)) // 이렇게 acc 값을 전달 해주지 않아도 됩니다.
오늘은 map, filter, reduce 가 실제로 어떤 형태로 작동되는 지에 대해서 알아보았습니다!
확실히 내부 구조를 알게되니 자바스크립트에 대한 이해도가 높아지는 것 같습니다! 👍🏻