본문 바로가기
프로그래밍 언어/Javascript

고차함수 설계 : arr.map() / arr.reduce() / arr.filter()

by whale in milktea 2023. 2. 16.

객체와 배열은 모든 프로그래밍 언어에서 다루는 개념이며, 특히 객체지향 프로그래밍에 있어서 중요한 역할을 맡는다.

이 중, 배열을 활용한 데이터의 조작은 프로그래밍을 통해 특정한 화면 및 데이터를 구현하고자 할 때 항상 사용되는 개념이다.

이에 본 포스팅에서는 가장 자주 사용되는 배열의 개념인 arr.map(), arr.reduce(), arr.filter()를 살펴보고 이를 다루는 예제를 살펴보고자 한다.

 

다만, 현재 배열을 고차함수(콜백함수)를 활용해서 이해하는 역량이 많이 부족하기 때문에 MDN에서 제공하는 프로토타입을 기준으로 쪼개보고 이 쪼갠 내용을 바탕으로 예시코드를 살펴봄으로 내용을 정리하고자 한다.

 

Arr.Map()

// MDN 프로토타입
arr.map(callback(currentValue[, index[, array]])[, thisArg])

이 경우, 다음과 같은 4가지 경우로 쪼개봤다.

1. (currentValue) 만 사용할 때,
2. (currentValue[, index])까지 사용할 때,
3. (callback(currentValue[, index[, array]])까지 사용할 때,
4. (callback(currentValue[, index[, array]])[, thisArg])까지 사용할 때

각각의 예시코드를 살펴보면서 이해해보고자 한다.

1. (currentValue) 만 사용할 때,

const arr = [1, 2, 3, 4, 5];
const doubledArr = arr.map(num => num * 2);
console.log(doubledArr); // [2, 4, 6, 8, 10]

이 코드에서는 주어진 배열 arr의 요소를 arr.map메서드를 통해 콜백함수의 인자로 전달하고 있다.

인자로 전달된 배열은 arr.map()메서드에 의해 콜백함수 내부에서 순회하게 되며 콜백함수에서 정의된 식에 의해 다른 값으로 변경되고 새로운 배열에 담기게 된다.

 

2. (currentValue[, index])까지 사용할 때,

const arr = ['apple', 'banana', 'orange'];
const fruitsWithIndex = arr.map((fruit, index) => `${index + 1}. ${fruit}`);
console.log(fruitsWithIndex); // ['1. apple', '2. banana', '3. orange']

이 코드에서는 주어진 배열 arr요소와 인덱스 arr.map메서드를 통해 콜백함수의 인자로 전달하고 있고, 동시에 index 또한 인자로 전달하고 있다.

인자로 전달된 인덱스와 요소는 arr.map()메서드에 의해 콜백함수 내부에서 순회하게 되며 콜백함수에서 정의된 식에 의해 다른 값으로 변경된다.

다만, 이 부분에서 위 코드와의 차이는 인자로 index와 value가 동시에 전달되고 있다는 점이다.

 

이 함수에 index와 value는 인자로 전달됨으로 각각 독립적인 value가 되며 함수에 정의된 템플릿 리터럴 식을 통해 새로운 배열에 담기게 된다.

 

3. (callback(currentValue[, index[, array]])까지 사용할 때,

const arr = [1, 2, 3];
const result = arr.map((currentValue, index, array) => {
  console.log(`currentValue: ${currentValue}`);
  console.log(`index: ${index}`);
  console.log(`array: ${array}`);
  return currentValue * 2;
});
console.log(result); // [2, 4, 6]

 

이 코드에서는 주어진 arr의 요소와 인덱스를 콜백함수의 인자로 전달하고 있다.

다만, 독특한 점은 배열 자체를 콜백함수에 인자로 전달하고 있다는 점이다.

 

여기서 arr.map의 핵심개념을 이해해야 한다.

❌ arr.map()함수는 절대 그 배열 자체를 콜백함수에 인자로 전달되는 개념이 아니라,

1️⃣ 각 요소에 대해 콜백함수를 호출하고

2️⃣ 콜백함수에 해당 요소를 인자로 전달하여

3️⃣ 리턴한 값을 새로운 배열에 담는 개념이다.

 

즉, 해당 개념에서는 각 요소에서 콜백함수를 호출하는 개념이 아닌 배열 자체에서 콜백함수를 호출하는 개념이다.

이 배열에 *2한 값이 리턴된다.

 

4. (callback(currentValue[, index[, array]])[, thisArg])까지 사용할 때

const obj = {
  multiplier: 2,
  multiply(num) {
    return num * this.multiplier;
  },
};

const arr = [1, 2, 3];
const result = arr.map(obj.multiply, obj);
console.log(result); // [2, 4, 6]

이 식은, 객체에 정의된 값을 arr.map()으로 사용하고 싶을 때 사용되는 사례이다.

muliplier는 2가 할당되어 있고, multiply 함수는 주어진 인자에 multiplier에 정의된 값을 곱할 수 있다.

 

즉, 이 경우에는 multiplier에 어떤 값이 정의되어 있든 arr.map()으로 호출하여 사용할 수 있다.

초기화된 arr는 obj.muliply함수를 호출하고 호출된 함수는 내부에 정의된 obj를 참조하여 정의된 식을 실행한다.

 

 

Array.prototype.reduce()

// MDN 프로토타입
arr.reduce(callback(accumulator, currentValue[, index[, array]])[, initialValue])

reduce() 메서드는 배열의 각 요소에 대해 콜백 함수를 호출하며, 콜백 함수의 반환 값을 누적하여 최종 결과 값을 생성한다.

이 경우에도 4가지 경우로 나누어 살펴보고자 한다.

 

1. (accumulator, currentValue)만 사용할 때,

const arr = [1, 2, 3, 4, 5]; 
const sum = arr.reduce((accumulator, currentValue) => accumulator + currentValue); 
console.log(sum); // 15

이 예제에서는 주어진 배열 arr의 요소를 순회하면서 각 요소를 누적하여 합계를 계산한다. 여기서 accumulator는 누적된 값이며, currentValue는 현재 배열 요소에 해당한다.

 

2. (accumulator, currentValue, index)까지 사용할 때,

const arr = [1, 2, 3, 4, 5];
const sumWithIndex = arr.reduce((accumulator, currentValue, index) => {
  console.log(`index: ${index}`);
  return accumulator + currentValue;
});
console.log(sumWithIndex); // 15

이 예제에서는 주어진 배열 arr의 요소와 인덱스를 콜백 함수의 인자로 전달하고 있다.

여기서 index는 배열 요소의 인덱스다.

 

3. (accumulator, currentValue, index, array)까지 사용할 때,

const arr = [1, 2, 3, 4, 5];
const sumWithDetails = arr.reduce((accumulator, currentValue, index, array) => {
  console.log(`accumulator: ${accumulator}`);
  console.log(`currentValue: ${currentValue}`);
  console.log(`index: ${index}`);
  console.log(`array: ${array}`);
  return accumulator + currentValue;
});
console.log(sumWithDetails); // 15

이 예제에서는 배열의 요소, 인덱스, 배열 자체를 콜백 함수의 인자로 전달하고 있다.

여기서 array는 원본 배열이다.

 

4. (accumulator, currentValue, index, array)와 initialValue까지 사용할 때,

const arr = [1, 2, 3, 4, 5];
const initialValue = 10;
const sumWithInitialValue = arr.reduce(
  (accumulator, currentValue, index, array) => {
    return accumulator + currentValue;
  },
  initialValue
);
console.log(sumWithInitialValue); // 25

이 예제에서는 초기값을 설정하여 reduce() 메서드를 호출한다. 여기서 initialValue는 누적 값의 초기 값을 의미한다. 초기값이 주어지면, 첫 번째 배열 요소의 인덱스가 0이 아닌 1에서 시작한다. 이렇게 설정하면 배열 요소의 합계에 초기값이 더해진 결과를 얻을 수 있다.

 

살펴보면 Arr.map과 크게 다른 점이 없다. 사실상 출력값과 실행문만 다르다고 봐도 무방하다.

 

 

Array.prototype.filter()

// MDN 프로토타입
arr.filter(callback(element[, index[, array]])[, thisArg])

filter() 메서드는 콜백 함수를 통해 배열 요소를 검사하여 조건에 맞는 요소만 모아 새로운 배열을 만듭니다.

이번에도 4가지 경우로 나눠서 살펴보고자 한다.

 

1. (element) 만 사용할 때,

const arr = [1, 2, 3, 4, 5];
const evenNumbers = arr.filter((num) => num % 2 === 0);
console.log(evenNumbers); // [2, 4]

이 코드에서는 주어진 배열 arr의 요소를 arr.filter 메서드를 통해 콜백함수의 인자로 전달하고 있다.

해당 함수는 조건에 맞는 요소만 새로운 배열에 담아 반환하고 있다.

 

2. (element[, index])까지 사용할 때,

const arr = ["apple", "banana", "orange", "grape"];
const evenIndexFruits = arr.filter((fruit, index) => index % 2 === 0);
console.log(evenIndexFruits); // ['apple', 'orange']

이 코드에서는 주어진 배열 arr의 요소와 인덱스를 arr.filter 메서드를 통해 콜백함수의 인자로 전달하고 있다.

해당 함수는 인덱스가 짝수인 요소만 새로운 배열에 담아 반환한다.

 

3. (callback(element[, index[, array]])까지 사용할 때,

const arr = [10, 20, 30];
const greaterThanFirst = arr.filter((num, index, array) => num > array[0]);
console.log(greaterThanFirst); // [20, 30]

이 코드에서는 주어진 arr의 요소와 인덱스를 콜백함수의 인자로 전달하고 있다.

배열 자체도 콜백함수에 인자로 전달하고 있다.

이 함수는 첫 번째 요소보다 큰 요소만 새로운 배열에 담아 반환하는 자바스크립트 함수이다.

 

4. (callback(element[, index[, array]])[, thisArg])까지 사용할 때

const obj = {
  min: 2,
  greaterThanMin(num) {
    return num > this.min;
  },
};

const arr = [1, 2, 3, 4, 5];
const result = arr.filter(obj.greaterThanMin, obj);
console.log(result); // [3, 4, 5]

이 코드는 객체에 정의된 값을 arr.filter()로 사용하고 싶을 때 사용되는 사례에 해당한다.

min은 2로 정의되어 있고, greaterThanMin 함수는 주어진 인자가 min보다 큰지 비교하게 된다.

최종적으로 이 함수는 min보다 큰 요소만 새로운 배열에 담아 반환하는 함수이다.