— JavaScript, 함수형 프로그래밍 — 1 min read
개발할 때 늘 도움을 주는 우리 형, 함수형을 소개합니다
형은 대체로 순수해서 대하기 편하지만, 가끔 까다로운 경우가 있었습니다. 제가 함수의 역할을 잘못 판단하는 경우죠. 개발 할 때 forEach
와 map
을 종종 헷갈리곤 했습니다. 배열을 순서대로 돌면서 어떤 행동을 할지 정의하는 함수라 크게 다르지 않다고 생각했거든요. 이런 저의 생각을 우리 형은 늘 못마땅해했습니다. 두 함수의 역할이 분명히 다르다는 겁니다. 이름이 다르니까 분명 뭐가 다르겠지 싶었지만, 뭐가 다른지 이해하기 어려웠습니다. 사용해보면 크게 다르지 않거든요. 형은 어리둥절하는 저를 보곤 이렇게 말했습니다. "리턴 값을 한번 봐."
1const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];2
3const result1 = arr.forEach(n => n);4const result2 = arr.map(n => n);5
6console.log(reuslt1); // undefined7console.log(result2); // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
두 함수의 리턴 값은 분명 달랐습니다. forEach
는 undefined
를 반환했고 map
은 배열을 반환했죠. 가만 보니 map
은 이름대로 결괏값을 매핑하는 함수인 것 같았습니다. 심지어 forEach
가 하는 일(순회)도 할 수 있었습니다. 이제는 forEach
대신 map
만 쓰면 되겠구나 싶었습니다. 형은 반만 맞았다고 말했습니다. 단순히 순차적으로 조회할 땐 forEach
를 써야 한다고 했습니다. 역할에 맞는 순간에 사용해야 한다는 것이었죠. 왜 굳이 두 개를 따로 써야 하는지 저는 여전히 의문이었습니다.
1const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];2const limit = 1000000;3
4console.time('forEach');5let i = 0;6while (i++ < limit) arr.forEach(n => n);7console.timeEnd('forEach'); // forEach: 36.455078125ms8
9console.time('map');10let j = 0;11while (j++ < limit) arr.map(n => n);12console.timeEnd('map'); // map: 69.7138671875ms
극단적인 상황이지만 속도가 두배 가까이 차이가 났습니다. 생각해보니 이유는 분명했습니다. map
이 하는 일이 더 많았기 때문이죠. 정말 결괏값을 이용하기 위해, 매핑하기 위해 사용하는게 아니라면 forEach
를 사용하는게 맞다는 확신이 생겼습니다. 성능적으로 손해를 보기 싫다면 말이죠. 미비한 차이지만 이렇게 역할의 차이를 분명히 알고 필요에 맞게 골라 쓰는게 함수형, 우리형의 매력이라는 생각이 드네요.