1. Map
function myMap(list, func) {
let result = [];
for (let i = 0; i < list.length; i++) {
result.push(func(list[i]));
}
return result;
}
const list = [1, 2, 3, 4];
const example = list.map((x) => (x % 2 === 0 ? true : false));
console.log(example);
console.log(myMap(list, (x) => (x % 2 === 0 ? true : false)));
map 함수 내부를 구현해보았다. 어려운 것은 아니고, 따로 myMap을 만들어서 내부적으로 어떻게 동작하는지 짐작하여 구현해보았다.
여기에서 중요한 포인트는 Javascript에서는 일급 객체인 함수를 매개 변수로, 인자로, 리턴값으로 사용할 수 있다는 것이다.
따라서 func라는 매개 변수를 두었기에 인자로 함수를 받을 수 있었다.
2. Filter
function myFilter(list, func) {
let result = [];
for (let i = 0; i < list.length; i++) {
if (func(list[i])) {
result.push(func(list[i]));
}
}
return result;
}
const list = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
const example = list.filter((x) => x % 2 === 0);
console.log(example);
console.log(myFilter(list, (x) => x % 2 === 0));
filter는 위의 map에서 if문 1줄만 추가하면 된다. map은 list.length 길이와 return값의 length 길이가 같아야하고, 전체 원소에 적용할 수 있는 함수인데에 비해 filter는 원하는 조건의 요소만 반환 받을 수 있다. 그래서 map과 filter는 적재적소에 맞게 활용해야 한다.
3. reduce
먼저 간단하게 1부터 10까지 더하는 연산을 하는 reduce function을 사용해봅시다.
const list = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
const reduceSum = list.reduce(function (acc, value) {
console.log(`acc : ${acc} `);
console.log(`value : ${value} `);
return acc + value;
});
중간에 accumulate와 value값을 log로 찍어 작동 방식에 대해 파악해보려고 합니다. 위의 출력은 log만 찍어본 것이고, 좀 더 보기 쉽게 log를 다시 찍어보겠습니다.
const reduceSum = list.reduce(function (acc, value) {
console.log(`${acc} + ${value} = ${acc + value}`);
return acc + value;
});
acc값에 list 배열의 가장 첫 번째 값을 먼저 넣어두고 누산을 시작합니다. acc에 value를 더하고, 더해서 acc값에 다시 넣고 또 value와 넣는 꼴의 반복입니다. 이렇게만 보면 참 쉬운데, 배열 내에 문자열이나 객체로 연산을 하라고 하면 상당히 헷깔릴 것 같습니다.
대략 어떻게 사용하는지 알았으니 이제 reduce 함수는 내부적으로 어떻게 구현되어 있을지 유추해보고자 합니다.
const list = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
/**
* (1) Reduce 내부 구현
*/
function myReduce1(list, func, init) {
let acc = init;
for (let i = 1; i < list.length; i++) {
let value = list[i];
console.log(`[myReduce 1] ${acc} + ${value} = ${func(acc, value)}`);
acc = func(acc, value);
}
return acc;
}
let myReduceResult = myReduce1(
list,
function (acc, value) {
return acc + value;
},
list[0]
);
console.log(`myReduce1 : ${myReduceResult}`);
/**
* (2) Reduce
* 초깃값 설정 없음
*/
const myReduce2 = list.reduce(function (acc, value) {
console.log(`[myReduce 2] ${acc} + ${value} = ${acc + value}`);
return acc + value;
});
let reduceResult = myReduce2;
console.log(`myReduce2 : ${reduceResult}`);
오래 걸릴 일은 아닌데 초깃값 설정을 어떻게 했을지 유추하다보니 시간이 좀 걸렸습니다.
myReduce2는 reduce 그대로 사용한 것인데, 초깃값을 매개변수로 던져주지 않았습니다. 기본적으로 설정된 매개변수는 아마도 배열의 첫 번째 요소이지 않을까 싶었습니다.
초깃값을 0으로 시작하고 reduce를 돌리니 기존 reduce 함수와 log 찍히는게 다르더라구요. 그래서 기본적으로 내장된 reduce 함수는 배열 첫 번째 요소를 accumulate에 먼저 담고 시작하지 않을까 싶었습니다.
'개발 > ES6' 카테고리의 다른 글
Lodash Zip() : Reduce로 구현해보기 (0) | 2023.10.12 |
---|---|
함수형 프로그래밍 - Reduce를 활용하여 Map, Filter 구현하기 (0) | 2023.10.10 |
Javascript ES6 - Set 기능 내부 구현해보기 (0) | 2023.10.08 |