JavaScript 배열 고차 함수 - forEach, map, filter, reduce

2025. 12. 10. 18:22·FrontEnd/JavaScript

앞에서 for, while, for...of 같은 반복문들로

"어떻게 도는지"를 직접 제어하는 방법을 봤다.

이번에는 한 단계만 더 올라가서,
배열에서 정말 자주 보게 되는 고차 함수 4종 세트를 정리해보려고 한다.

  • forEach
  • map
  • filter
  • reduce

이 네 개만 제대로 익혀도,
데이터를 순회하고 가공하는 코드가 훨씬 깔끔해진다.


결론 먼저

  • forEach: 단순히 "각 요소에 대해 어떤 작업을 한다" → 결과를 모으지 않음
  • map: 각 요소를 변환해서 새 배열을 만든다
  • filter: 조건을 만족하는 요소만 골라서 새 배열을 만든다
  • reduce: 배열 전체를 하나의 값으로 축약한다 (합계, 평균, 객체로 묶기 등)

아주 짧게 요약하면 나는 이렇게 쓴다

  • 부수 효과(로그 찍기, DOM 조작 등)만 필요 → forEach
  • 배열을 다른 배열로 변환 → map
  • 배열에서 일부만 걸러내기 → filter
  • 배열 → 숫자/문자열/객체 등 단일 값으로 만들기 → reduce

왜 굳이 고차 함수냐?

"그냥 for로 돌면 되는 거 아닌가?" 라는 생각이 들 수 있다.

물론 가능하다. 실제로도 for만으로 대부분 할 수 있다.

하지만 고차 함수들은 의도를 코드에 그대로 드러내기 쉽다는 장점이 있다. -> 빠르게 읽고 해석할 수 있음

예를 들어, 배열을 2배로 만드는 코드를 보자.

const nums = [1, 2, 3];

// for 버전
const doubled1 = [];
for (let i = 0; i < nums.length; i++) {
  doubled1.push(nums[i] * 2);
}

// map 버전
const doubled2 = nums.map(n => n * 2);

둘 다 결과는 같다. 하지만 읽을 때 느낌은 다르다.

  • for 버전: "i를 0부터 length까지 돌리고, 각 요소를 꺼내서 2배를 해서 새 배열에 push한다"
  • map 버전: "이 배열을 변환해서 새 배열을 만든다"

이게 고차 함수의 핵심이다.

"어떻게 도는가"보다 "무엇을 하고 싶은가"를 더 잘 보여줄 수 있다고 생각한다.


1. forEach – 단순 순회 + 부수 효과

forEach는 배열의 각 요소에 대해 콜백 함수를 실행한다.

const nums = [1, 2, 3];

nums.forEach((value, index) => {
  console.log(index, value);
});
// 0 1
// 1 2
// 2 3

콜백의 기본 형태는

arr.forEach((value, index, array) => {
  // value: 현재 요소
  // index: 현재 인덱스
  // array: 원본 배열
});

중요한 포인트

  • forEach는 항상 undefined를 반환한다
  • 즉, forEach 자체로 새 배열을 만들 수 없다
const nums = [1, 2, 3];

const result = nums.forEach(n => n * 2);

console.log(result); // undefined

그래서 forEach는 주로

  • 로그 찍기
  • DOM 조작
  • 외부 변수에 값 쌓기

등 부수 효과(side effect)가 필요할 때 쓴다.


2. map – 배열을 변환해서 새 배열 만들기

map은 배열의 각 요소를 변환(transform) 해서 새 배열을 만든다.

const nums = [1, 2, 3];

const doubled = nums.map(n => n * 2);

console.log(doubled);
// [2, 4, 6]
console.log(nums);
// [1, 2, 3] (원본 유지)

기본 형태는 forEach와 비슷하다.

const newArray = arr.map((value, index, array) => {
  return /* 새 값 */;
});
  • 콜백이 무엇을 반환하느냐에 따라 새 배열의 요소가 결정된다
  • 원본 배열은 바뀌지 않고, 항상 같은 길이의 새 배열이 반환된다

예시: 유저 객체 배열에서 이름만 뽑기

const users = [
  { id: 1, name: 'Lee' },
  { id: 2, name: 'Kim' },
];

const names = users.map(user => user.name);

console.log(names);
// ['Lee', 'Kim']

언제 map?

  • 배열을 그대로 돌리되, 형태만 바꾸고 싶을 때
  • 예: 숫자 → 문자열, 객체 → 다른 형태의 객체, 등

3. filter – 조건을 만족하는 것만 추리기

filter는 말 그대로 걸러내는 함수다.

  • 콜백에서 true를 반환한 요소만 새 배열에 남는다
  • 원본 배열은 변경되지 않는다
const nums = [1, 2, 3, 4, 5];

const even = nums.filter(n => n % 2 === 0);

console.log(even);
// [2, 4]

기본 형태는

const filtered = arr.filter((value, index, array) => {
  return /* 조건: true/false */;
});

예시: 활성 유저만 고르기

const users = [
  { id: 1, name: 'Lee', active: true },
  { id: 2, name: 'Kim', active: false },
  { id: 3, name: 'Park', active: true },
];

const activeUsers = users.filter(user => user.active);

console.log(activeUsers);
// [ { id: 1, ... }, { id: 3, ... } ]

언제 filter?

  • 배열에서 일부만 골라내고 싶을 때
  • 예: 특정 조건의 유저, 특정 타입의 값, 특정 상태의 아이템 등

4. reduce – 배열 전체를 하나의 값으로 축약하기

reduce는 고차 함수 중에서 가장 헷갈리지만,
익숙해지면 가장 강력한 도구다.

기본 개념은 이렇다.

배열의 모든 요소를 왼쪽에서 오른쪽으로 돌면서, 하나의 값으로 "축약"한다.

기본 형태

const result = arr.reduce((accumulator, currentValue, index, array) => {
  // accumulator: 누적 값
  // currentValue: 현재 요소
  return /* 다음 누적 값 */;
}, initialValue);

예시 1) 합계 구하기

const nums = [1, 2, 3, 4];

const sum = nums.reduce((acc, n) => {
  return acc + n;
}, 0);

console.log(sum);
// 10

동작 흐름은 이렇게 된다

  • 초기 acc = 0
  • 1번째 요소: acc = 0 + 1 → 1
  • 2번째 요소: acc = 1 + 2 → 3
  • 3번째 요소: acc = 3 + 3 → 6
  • 4번째 요소: acc = 6 + 4 → 10

예시 2) 객체로 묶기

const users = [
  { id: 1, name: 'Lee' },
  { id: 2, name: 'Kim' },
  { id: 3, name: 'Park' },
];

const userMap = users.reduce((acc, user) => {
  acc[user.id] = user;
  return acc;
}, {});

console.log(userMap);
// {
//   1: { id: 1, name: 'Lee' },
//   2: { id: 2, name: 'Kim' },
//   3: { id: 3, name: 'Park' },
// }

이렇게 reduce는 숫자 합계뿐 아니라,

  • 객체로 인덱싱하기
  • 그룹핑하기
  • 통계 값(최대/최소/평균) 구하기

같은 작업에도 많이 쓰인다.

언제 reduce?

  • 배열을 돌면서 어떤 누적 결과 하나를 만들어야 할 때
  • 그 결과가 숫자, 문자열, 객체, 배열 등 어떤 형태든 상관없다

네 가지를 한 번에 비교해 보기

같은 배열에 대해, 4가지 함수를 각자 어떻게 쓰는지 비교해 보면 느낌이 더 잘 온다.

const nums = [1, 2, 3, 4];

// 1) forEach: 그냥 돌면서 로그만 찍기
nums.forEach(n => {
  console.log('값:', n);
});

// 2) map: 모든 값에 2배 해서 새 배열 만들기
const doubled = nums.map(n => n * 2);
// [2, 4, 6, 8]

// 3) filter: 짝수만 뽑기
const even = nums.filter(n => n % 2 === 0);
// [2, 4]

// 4) reduce: 합계 구하기
const sum = nums.reduce((acc, n) => acc + n, 0);
// 10

요약하면

  • forEach: "그냥 한 바퀴 돌면서 ~~한다"
  • map: "각 요소를 ~~로 바꿔서 새 배열 만든다"
  • filter: "조건 만족하는 것만 남겨서 새 배열 만든다"
  • reduce: "전체를 하나의 결과로 만든다"

for vs forEach vs map vs filter vs reduce 선택 기준

실제 코드 짤 때, 머릿속에서 이렇게 고르면 편하다.

  • 반복이 필요하다 → 근데 결과값을 따로 만들 필요는 없다
    • 로그 찍기, DOM 조작, 외부 상태 업데이트
    • → forEach 또는 그냥 for
  • 배열을 -> 다른 배열로 바꾸고 싶다
    • 길이는 같고, 값만 바뀌는 경우 → map
    • 일부만 남기고 싶다 → filter
  • 배열 전체에서 숫자/문자열/객체 하나를 뽑아내고 싶다
    • 합계, 평균, 카운트, 맵/그룹, 통계 등 → reduce
  • 성능이 극단적으로 민감한 구간이다
    • → 가장 단순한 for 문이 유리한 경우도 있다 (특히 큰 배열 + 빈번한 호출)
    • 다만 일반적인 서비스 코드에서는 가독성 > 미세한 성능 차이인 경우가 훨씬 많다

오늘 내용 한 줄씩 다시 정리

  • forEach: 부수 효과용. 새 배열을 만들고 싶을 땐 쓰지 않는다.
  • map: "배열을 변환해서 새 배열" 만드는 도구.
  • filter: "조건을 만족하는 요소만 남겨서 새 배열" 만드는 도구.
  • reduce: "배열 전체를 하나의 값으로 축약"하는 도구.
  • 고차 함수는 결국, 빠르게 읽고 해석할 수 있음
저작자표시 비영리 변경금지 (새창열림)

'FrontEnd > JavaScript' 카테고리의 다른 글

JavaScript 배열 고차 함수 - some, every, find, findIndex (조건 탐색 편)  (0) 2025.12.10
JavaScript 컬렉션 - Set  (0) 2025.12.10
JavaScript 기본기 정리 – 반복문·배열·문자열·Math 한 장에 모으기  (0) 2025.11.04
JavaScript 컬렉션 - Array  (0) 2025.09.09
JavaScript 컬렉션 - Map  (0) 2025.09.09
'FrontEnd/JavaScript' 카테고리의 다른 글
  • JavaScript 배열 고차 함수 - some, every, find, findIndex (조건 탐색 편)
  • JavaScript 컬렉션 - Set
  • JavaScript 기본기 정리 – 반복문·배열·문자열·Math 한 장에 모으기
  • JavaScript 컬렉션 - Array
프론트엔드 개발자 jbeat
프론트엔드 개발자 jbeat
프론트엔드 개발자 블로그인데 일상도 쪼그으믐
  • 프론트엔드 개발자 jbeat
    jbeat 님의 블로그
    프론트엔드 개발자 jbeat
  • 전체
    오늘
    어제
    • 분류 전체보기 (44)
      • FrontEnd (43)
        • TypeScript (6)
        • JavaScript (18)
        • Next.js (3)
        • React (1)
        • Testing (2)
        • Third Party (1)
        • web (10)
        • Tooling (1)
        • coding test (0)
        • A.I (1)
      • 일상 (1)
        • wedding (1)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 인기 글

  • 태그

    Utility
    CRDT
    omit
    이터러블
    pick
    WebSocket
    CrossOrigin
    playwright
    Android
    컬렉션
    preconnect
    TypeScript
    javascript
    yjs
    주니어
    타입스크립트
    Next.js
    코테
    배열
    고차함수
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.5
프론트엔드 개발자 jbeat
JavaScript 배열 고차 함수 - forEach, map, filter, reduce
상단으로

티스토리툴바