JavaScript

[JavaScript] 고차함수

dearlhy 2025. 1. 29. 11:46

JavaScript에서 자주 쓰이는 고차 함수

JavaScript에는 이미 정의된 고차 함수들이 많습니다. 배열 메서드에서 특히 자주 사용됩니다.

1. forEach()란?

forEach()는 JavaScript 배열(Array)의 메서드로, 배열의 각 요소를 순회하며 주어진 함수를 실행하는 역할을 합니다.
즉, forEach()는 배열에 저장된 요소마다 한 번씩 특정 작업을 수행할 때 사용됩니다.

1) 기본 문법

array.forEach(callbackFunction(currentValue, index, array));

2) 매개변수 설명

  1. callbackFunction (필수): 각 배열 요소에서 실행할 함수
  2. currentValue (필수): 현재 처리 중인 배열 요소
  3. index (선택): 현재 요소의 인덱스
  4. array (선택): forEach()가 호출된 원본 배열

3) forEach()의 기본 사용법

const fruits = ["사과", "바나나", "포도"];

fruits.forEach(function (fruit) {
  console.log(fruit);
});
  • 화살표 함수(Arrow Function)를 사용하면 더 간결하게 작성할 수 있습니다.
fruits.forEach((fruit) => console.log(fruit));
사과
바나나
포도

4) forEach()의 다양한 활용법

  • 배열 요소와 인덱스 함께 사용하기
const colors = ["빨강", "파랑", "초록"];

colors.forEach((color, index) => {
  console.log(`${index + 1}번째 색상: ${color}`);
});
1번째 색상: 빨강
2번째 색상: 파랑
3번째 색상: 초록
  • 객체 배열을 순회하며 특정 속성 출력하기
const users = [
  { name: "Alice", age: 25 },
  { name: "Bob", age: 30 },
  { name: "Charlie", age: 35 }
];

users.forEach((user) => {
  console.log(`${user.name}의 나이는 ${user.age}세입니다.`);
});
Alice의 나이는 25세입니다.
Bob의 나이는 30세입니다.
Charlie의 나이는 35세입니다.

5) forEach() 사용 시 주의할점

break 또는 return 사용 불가능

  • forEach()는 반복문이 아니라 콜백 함수를 실행하는 메서드이므로 break, continue, return을 사용할 수 없습니다.
  • 만약 특정 조건에서 반복을 중단해야 한다면, forEach() 대신 for...of 또는 some(), every()를 사용해야 합니다.
const numbers = [1, 2, 3, 4, 5];

numbers.forEach((num) => {
  if (num === 3) {
    return; // 무시됨! (반복문이 중단되지 않음)
  }
  console.log(num);
});
1
2
4
5

 

2. map()이란?

map()은 JavaScript 배열(Array)의 메서드 중 하나로, 배열의 각 요소를 변환하여 새로운 배열을 생성하는 함수입니다.
기존 배열을 변경하지 않고, 새로운 배열을 반환한다는 점이 forEach()와의 큰 차이점입니다.

1) 기본 문법

const newArray = array.map(callbackFunction(currentValue, index, array));

매개변수 설명

  1. callbackFunction (필수): 각 배열 요소에서 실행할 함수
  2. currentValue (필수): 현재 처리 중인 배열 요소
  3. index (선택): 현재 요소의 인덱스
  4. array (선택): map()이 호출된 원본 배열
  • map()은 새로운 배열을 반환하며, 원본 배열을 변경하지 않습니다.

2) map() 기본 사용법

  • 배열의 각 요소를 변환하기
const numbers = [1, 2, 3, 4, 5];

const doubled = numbers.map(num => num * 2);

console.log(doubled); // [2, 4, 6, 8, 10]
console.log(numbers); // [1, 2, 3, 4, 5] (원본 배열 유지)
  • forEach()와 달리, map()은 새로운 배열을 반환합니다.

3) map()의 다양한 활용법

  • 배열의 문자열 변환
const names = ["alice", "bob", "charlie"];

const capitalizedNames = names.map(name => name.toUpperCase());

console.log(capitalizedNames); // ["ALICE", "BOB", "CHARLIE"]
  • map()을 사용하여 문자열을 변환할 수 있습니다.
  • 객체 배열 변환하기
const users = [
  { name: "Alice", age: 25 },
  { name: "Bob", age: 30 },
  { name: "Charlie", age: 35 }
];

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

console.log(userNames); // ["Alice", "Bob", "Charlie"]
  • 객체 배열에서 특정 속성만 추출할 때도 유용하게 사용할 수 있습니다.
  • 인덱스를 활용하여 새로운 배열 만들기
const numbers = [10, 20, 30];

const indexedNumbers = numbers.map((num, index) => `Index ${index}: ${num}`);

console.log(indexedNumbers);
// ["Index 0: 10", "Index 1: 20", "Index 2: 30"]
  • map()의 두 번째 매개변수인 index를 사용하여 배열 요소의 인덱스를 활용할 수도 있습니다.

4) map() 사용 시 주의할 점

  • map()은 반드시 새로운 배열을 반환하므로, return을 생략하면 배열 요소가 undefined가 됩니다.
const numbers = [1, 2, 3];

const result = numbers.map(num => {
  num * 2; // ❌ return을 생략함
});

console.log(result); // [undefined, undefined, undefined]
  • 해결 방법: return을 추가하기
const result = numbers.map(num => num * 2);
console.log(result); // [2, 4, 6]

3. filter()란?

filter()는 JavaScript 배열 메서드 중 하나로, 특정 조건을 만족하는 요소만 걸러서 새로운 배열을 반환하는 함수입니다.
원본 배열을 변경하지 않고, 조건에 맞는 요소들만 포함하는 새로운 배열을 생성합니다.

1) 기본 문법

const newArray = array.filter(callbackFunction(currentValue, index, array));

매개변수 설명

  1. callbackFunction (필수): 각 배열 요소에서 실행할 함수
  2. currentValue (필수): 현재 처리 중인 배열 요소
  3. index (선택): 현재 요소의 인덱스
  4. array (선택): filter()가 호출된 원본 배열
  • filter()는 true를 반환하는 요소만 새로운 배열에 포함합니다.

2) filter() 기본 사용법

  • 짝수만 걸러내기
const numbers = [1, 2, 3, 4, 5, 6];

const evenNumbers = numbers.filter(num => num % 2 === 0);

console.log(evenNumbers); // [2, 4, 6]
  • 특정 조건을 만족하는 객체 필터링
const users = [
  { name: "Alice", age: 25 },
  { name: "Bob", age: 17 },
  { name: "Charlie", age: 30 }
];

const adults = users.filter(user => user.age >= 18);

console.log(adults);
// [{ name: "Alice", age: 25 }, { name: "Charlie", age: 30 }]
  • 문자열 배열에서 특정 단어가 포함된 요소 찾기
const words = ["apple", "banana", "cherry", "avocado"];

const aWords = words.filter(word => word.startsWith("a"));

console.log(aWords); // ["apple", "avocado"]
  • 중복 제거 (Set과 함께 활용)
const numbers = [1, 2, 2, 3, 4, 4, 5];

const uniqueNumbers = numbers.filter((num, index, arr) => arr.indexOf(num) === index);

console.log(uniqueNumbers); // [1, 2, 3, 4, 5]
  • 배열에서 null 또는 undefined 값 제거
const mixedArray = [1, null, 2, undefined, 3, "", 4, 0, false];

const validValues = mixedArray.filter(value => value);

console.log(validValues); // [1, 2, 3, 4]

3) filter() 사용 시 주의할 점

  • filter()는 항상 새로운 배열을 반환
const numbers = [1, 2, 3, 4, 5];

const filtered = numbers.filter(num => num > 2);

console.log(filtered); // [3, 4, 5]
console.log(numbers); // [1, 2, 3, 4, 5] (원본 배열 유지)
  • filter() 에서 return을 생략하면 undefined가 반환됨
const numbers = [1, 2, 3, 4, 5];

const result = numbers.filter(num => {
  num > 2; // ❌ return을 생략하면 항상 undefined가 반환됨
});

console.log(result); // []
  • 해결 방법: return 추가
const result = numbers.filter(num => num > 2);
console.log(result); // [3, 4, 5]

4. reduce()란?

reduce()는 JavaScript 배열 메서드 중 하나로, 배열의 모든 요소를 하나의 값으로 줄이는 함수입니다.
이를 통해 배열을 순회하며 누적 계산을 수행할 수 있습니다.

  • 배열의 총합 또는 계산
  • 배열에서 최댓값/최솟값 찾기
  • 객체 배열을 그룹화 또는 통계 값 계산
  • 배열을 다른 형식의 데이터로 변환

1) 기본 문법

const result = array.reduce(callbackFunction(accumulator, currentValue, index, array), initialValue);

매개변수 설명

  1. callbackFunction (필수): 배열의 각 요소에서 실행할 함수
    • accumulator: 누적값 (이전 반복의 반환값)
    • currentValue: 현재 처리 중인 배열 요소
    • index (선택): 현재 요소의 인덱스
    • array (선택): reduce()가 호출된 원본 배열
  2. initialValue (선택): accumulator의 초기값 (생략 시 배열의 첫 번째 요소 사용)

reduce()는 배열을 순회하며 누적 연산을 수행한 최종 결과를 반환합니다.

2) reduce() 기본 사용법

  • 배열의총합 구하기
const numbers = [1, 2, 3, 4, 5];

const sum = numbers.reduce((acc, num) => acc + num, 0);

console.log(sum); // 15
  • 배열 요소의 곱 구하기
const numbers = [2, 3, 4];

const product = numbers.reduce((acc, num) => acc * num, 1);

console.log(product); // 24
  • 최댓값/최솟값 찾기
const numbers = [10, 5, 8, 20, 3];

const max = numbers.reduce((acc, num) => (num > acc ? num : acc), numbers[0]);
const min = numbers.reduce((acc, num) => (num < acc ? num : acc), numbers[0]);

console.log(max); // 20
console.log(min); // 3
  • 객체 배열에서 특정 속성 값 합산하기
const orders = [
  { item: "Laptop", price: 1000 },
  { item: "Phone", price: 500 },
  { item: "Tablet", price: 700 }
];

const totalPrice = orders.reduce((acc, order) => acc + order.price, 0);

console.log(totalPrice); // 2200
  • 배열을 객체 형태로 그룹화
const users = [
  { name: "Alice", age: 25 },
  { name: "Bob", age: 30 },
  { name: "Charlie", age: 25 },
  { name: "David", age: 30 }
];

const groupedByAge = users.reduce((acc, user) => {
  acc[user.age] = acc[user.age] || [];
  acc[user.age].push(user);
  return acc;
}, {});

console.log(groupedByAge);
/*
{
  25: [{ name: "Alice", age: 25 }, { name: "Charlie", age: 25 }],
  30: [{ name: "Bob", age: 30 }, { name: "David", age: 30 }]
}
*/

3) reduce() 사용 시 주의할 점

  • 초기값을 지정하지 않으면 첫 번째 요소가 초기값이 됨
const numbers = [10, 20, 30];

const sum = numbers.reduce((acc, num) => acc + num); // 초기값 미설정

console.log(sum); // 60
  • 빈 배열일 경우 초기값을 반드시 설정하세요.
const sum = numbers.reduce((acc, num) => acc + num, 0);

JavaScript 배열 메서드 비교 (forEach, map, filter, reduce)

forEach() 배열을 순회하며 각 요소에 대해 특정 작업 수행 ❌ 반환값 없음 (undefined) ❌ 변경하지 않음 단순 반복 작업 (콘솔 출력, DOM 조작 등)
map() 배열의 각 요소를 변환하여 새로운 배열 생성 ✅ 새로운 배열 반환 ❌ 변경하지 않음 모든 요소를 변환하고 싶을 때 (ex: 배열 값 변경)
filter() 조건을 만족하는 요소만 새로운 배열로 반환 ✅ 새로운 배열 반환 ❌ 변경하지 않음 특정 조건을 만족하는 요소만 추출하고 싶을 때
reduce() 배열을 순회하며 값을 누적하여 하나의 결과값 반환 ✅ 누적된 값 반환 ❌ 변경하지 않음 총합, 평균, 객체 변환 등 데이터 축소 작업

고차 함수의 장점

  1. 코드의 재사용성 증가
    고차 함수를 사용하면 반복적인 작업을 추상화하여 재사용 가능한 코드를 만들 수 있습니다.
  2. 코드의 간결성
    복잡한 작업을 간단한 함수 조합으로 표현할 수 있습니다.
  3. 가독성 향상
    작업의 의도가 명확해지고, 유지보수가 쉬워집니다.
  4. 함수형 프로그래밍 구현 가능
    고차 함수는 함수형 프로그래밍의 핵심 요소로, 불변성과 선언적 코드를 작성하는 데 필수적입니다.

고차 함수의 한계와 주의점

  1. 익명 함수 남용
    너무 많은 익명 함수 사용은 가독성을 해칠 수 있습니다. 필요하면 함수 이름을 명시하세요.
  2. 과도한 중첩
    고차 함수를 많이 중첩해서 사용하면, 코드가 복잡해질 수 있습니다.
  3. 성능
    대규모 데이터에 대해 고차 함수를 사용할 경우, 성능 문제가 발생할 수 있습니다. 이런 경우, 효율적인 알고리즘 설계를 병행해야 합니다.

결론

고차 함수는 JavaScript의 강력함과 유연성을 보여주는 중요한 기능입니다.
코드를 더 읽기 쉽고 재사용 가능하게 만들어주며, 함수형 프로그래밍을 구현하는 데 필수적인 도구입니다.

자주 사용하는 배열 메서드(map, filter, reduce 등)부터 직접 고차 함수를 작성하며 활용법을 익혀보세요!

'JavaScript' 카테고리의 다른 글

[JavaScript] 비동기 프로그래밍 (Promise, async/await)  (0) 2025.01.31
[JavaScript] ES6+ 문법  (1) 2025.01.30
[JavaScript] 클로저(Closure)  (0) 2025.01.28
JavaScript 기본 문법  (0) 2025.01.28
JavaScript에 대해서  (1) 2025.01.28