든든한 우리 형, 함수형 - 역할의 차이

개발할 때 늘 도움을 주는 우리 형, 함수형을 소개합니다

역할의 차이

형은 대체로 순수해서 대하기 편하지만, 가끔 까다로운 경우가 있었습니다. 제가 함수의 역할을 잘못 판단하는 경우죠. 개발 할 때 forEachmap을 종종 헷갈리곤 했습니다. 배열을 순서대로 돌면서 어떤 행동을 할지 정의하는 함수라 크게 다르지 않다고 생각했거든요. 이런 저의 생각을 우리 형은 늘 못마땅해했습니다. 두 함수의 역할이 분명히 다르다는 겁니다. 이름이 다르니까 분명 뭐가 다르겠지 싶었지만, 뭐가 다른지 이해하기 어려웠습니다. 사용해보면 크게 다르지 않거든요. 형은 어리둥절하는 저를 보곤 이렇게 말했습니다. “리턴 값을 한번 봐.”

리턴 값의 차이

1
2
3
4
5
6
7
const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

const result1 = arr.forEach(n => n);
const result2 = arr.map(n => n);

console.log(reuslt1); // undefined
console.log(result2); // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

두 함수의 리턴 값은 분명 달랐습니다. forEachundefined를 반환했고 map은 배열을 반환했죠. 가만 보니 map은 이름대로 결괏값을 매핑하는 함수인 것 같았습니다. 심지어 forEach가 하는 일(순회)도 할 수 있었습니다. 이제는 forEach 대신 map만 쓰면 되겠구나 싶었습니다. 형은 반만 맞았다고 말했습니다. 단순히 순차적으로 조회할 땐 forEach를 써야 한다고 했습니다. 역할에 맞는 순간에 사용해야 한다는 것이었죠. 왜 굳이 두 개를 따로 써야 하는지 저는 여전히 의문이었습니다.

속도의 차이

1
2
3
4
5
6
7
8
9
10
11
12
const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
const limit = 1000000;

console.time('forEach');
let i = 0;
while (i++ < limit) arr.forEach(n => n);
console.timeEnd('forEach'); // forEach: 36.455078125ms

console.time('map');
let j = 0;
while (j++ < limit) arr.map(n => n);
console.timeEnd('map'); // map: 69.7138671875ms

극단적인 상황이지만 속도가 두배 가까이 차이가 났습니다. 생각해보니 이유는 분명했습니다. map이 하는 일이 더 많았기 때문이죠. 정말 결괏값을 이용하기 위해, 매핑하기 위해 사용하는게 아니라면 forEach를 사용하는게 맞다는 확신이 생겼습니다. 성능적으로 손해를 보기 싫다면 말이죠. 미비한 차이지만 이렇게 역할의 차이를 분명히 알고 필요에 맞게 골라 쓰는게 함수형, 우리형의 매력이라는 생각이 드네요.