JavaScript for 대신 for...of, forEach, reduce, map

JavaScript for for...of forEach reduce map
JavaScript 루프(반복)문을 대표하는 for문과 for문을 대신하는 for...of문, forEach() 메서드, reduce() 메서드, map() 메서드에 대해서 소개합니다.

코딩할 때, 반복 처리가 필요한 상황에서 왠지 모르게 가장 먼저 떠오르는 것은 for 구문 입니다. 하지만 바로 'for는 좀 촌스럽고 코드가 복잡해 보여 가독성이 떨어져'라는 생각의 저항에 부딪히게 됩니다.

이런저런 이유로 for문을 대체할 수 있는 코드가 필요한 경우가 있습니다. 그래서 for문, for...of문, forEach() 메서드, reduce() 메서드, map() 메서드로 우리나라의 총 인구수를 구하는 코드를 작성해 보겠습니다. 모두 같은 결과를 냅니다.

우리는 실제로 항상 논리적인 근거로 어떤 구문·함수를 선택하며 코딩을 하는 것은 아닙니다. 거의 개인적인 습관과 취향으로 코드를 짜고 있습니다.



[공통 코드]
 // 우리나라 시도별 인구수를 가진 배열
 const arr = [
 // name: 시와 도 이름, value: 인구수
   {name: '경기', value: 13388000},
   {name: '서울', value: 9699000},
   {name: '부산', value: 3399000},
   {name: '경남', value: 3343000},
   {name: '인천', value: 2942000},
   {name: '경북', value: 2640000},
   {name: '대구', value: 2426000},
   {name: '충남', value: 2120000},
   {name: '전남', value: 1851000},
   {name: '전북', value: 1806000},
   {name: '충북', value: 1598000},
   {name: '강원', value: 1541000},
   {name: '대전', value: 1469000},
   {name: '광주', value: 1453000},
   {name: '울산', value: 1139000},
   {name: '제주', value: 672000},
   {name: '세종', value: 348000}
 ];
 
 // 총 인구수
 let sum = 0;

for문으로 처리

가독성: ★★★☆☆
처리 속도: ★★★★☆

같은 코드를 정해진 횟수만큼 반복해서 실행하고 싶은 경우에 사용하는 방법(구문)들 중에서 가장 일반적인 for문입니다.

 for (let i = 0; i < arr.length; i++) {
   sum += arr[i].value;
 }
공통 코드를 참고하세요.



for...of문으로 처리

가독성: ★★★★☆
처리 속도: ★★★★☆

최근 들어 깃허브 소스 코드에서 자주 보이는 for...of문은 ECMAScript 2015(공개일: 2015년 06월)부터 도입된 비교적 신선한 구문입니다. for문과는 달리 반복 횟수를 지정하지 않아도 되고 인덱스 변수 선언이나 대괄호([ ])를 사용하지 않아도 됩니다.

 for (const element of arr) {
   sum += element.value;
 }
공통 코드를 참고하세요.

주의 사항으로, IE(인터넷 익스플로러)에서는 동작하지 않습니다. 그리고 iterator(이터레이터)를 가진 Array(배열), Map(맵), DOM(돔) 컬렉션 등을 대상으로만 for...of문을 사용할 수 있습니다.

'iterator'는 값을 순서대로 끄집어낼 수 있도록 하는 것입니다.

Object(객체)를 대상으로는 for...of문을 사용하지 못하며 사용하면 'x is not iterable'라는 에러 메시지가 나옵니다. Object의 요소들을 반복 처리하고 싶다면 for...in문을 사용하세요.



forEach() 메서드로 처리

가독성: ★★★★☆
처리 속도: ★★★★☆

배열에서 사용할 수 있는 메서드이고 배열의 요소 하나하나를 파라미터로 받아서 정의한 콜백 함수를 실행합니다.

 arr.forEach(element => {
   sum += element.value;
 });
공통 코드를 참고하세요.

주의 사항으로, 반복 처리 도중에 종료하는 break문 또는 해당 조건만 건너뛰는 continue문은 콜백 함수에서 사용할 수 없습니다. 하지만 예외를 던지는 throw문으로 종료할 수 있었고 return문으로 해당 조건만 건너뛸 수 있었습니다.

참고로 forEach() 메서드는 reduce()·map() 메서드와는 달리 리턴 값이 'undefined'입니다.



reduce() 메서드로 처리

가독성: ★★★☆☆
처리 속도: ★★★☆☆

배열에서 호출이 가능한 메서드이고 콜백 함수의 파라미터(매개변수)에 배열의 요소 이외에 특히 콜백 함수의 리턴 값이 다음 차례에서 파라미터로 세팅되기 때문에 최종적으로 누적된 값을 반환하는 로직에 사용하면 적절하다고 생각합니다.

 sum = arr.reduce(
   // 콜백 함수
   (returnValue, element) => {
     return returnValue + element.value;
   },
   0 // returnValue 초기값
 );
공통 코드를 참고하세요.



map() 메서드로 처리

가독성: ★★★☆☆
처리 속도: ★★★☆☆

배열에서 사용하는 메서드이고 배열의 모든 요소를 인덱스 순서대로 처리하는 콜백 함수의 결과(리턴) 값으로 새로운 배열을 만들고 최종적으로 그 새 배열을 반환합니다. 그래서 반환되는 새 배열을 사용하지 않는 경우에도 단순히 배열의 요소를 반복 처리할 목적으로만 map() 메서드를 사용하는 것은 적절하지 못하다고 생각합니다.

 const newArray = arr.map(element => {
   return sum += element.value;
 });
공통 코드를 참고하세요.



속도 테스트 샘플 코드

for문, for...of문, forEach() 메서드, reduce() 메서드, map() 메서드로 속도 테스트를 해 보았습니다. 그런데 '데이터의 양(배열 요소의 수)·테스트 실행 횟수·테스트 케이스의 다양성'이 부족한 탓인지 기대하는 결과가 일관적으로 나오지 않았습니다. 그래서 아래에 소개하는 '속도 테스트 샘플 코드'만으로는 실행 결과에 큰 신뢰를 가지기 어렵다는 점 참고하세요. 하지만 데이터의 양을 늘리는 등의 추가 작업으로 테스트의 신뢰도를 높일 수 있습니다.

속도에 아주 민감한 대규모 프로젝트라면 전통적인 방식의 for문이나 이 글에서는 언급하고 있지 않지만 while문 또는 do...while문을 사용하는 것이 안전하다고 생각합니다.

전체 코드를 복사 & 붙여넣기로 브라우저 콘솔 등에서 바로 실행해 볼 수 있습니다.
#소프트웨어 개발

이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다.

댓글