본문 바로가기

JavaScript/공부공부

[JS] 고차함수 (1) map, filter, reduce

 

[ 고차함수 (Higher-order function) ]

함수형 프로그래밍에서 다른 함수를 인자로 받거나, 함수를 결과로 반환하는 함수. (추상화)

 


 

[ 함수를 인자로 받는 고차함수 ]

ex) 자바스크립트 배열 메소드  map( ), filter( ), reduce( )

 

( TypeScript 의 타입정의 )

* Array.prototype.map

 /**
     * Calls a defined callback function on each element of an array, and returns an array that contains the results.
     * @param callbackfn A function that accepts up to three arguments. The map method calls the callbackfn function                                                 one time for each element in the array.
     * @param thisArg An object to which the this keyword can refer in the callbackfn function. If thisArg is omitted,                                                 undefined is used as the this value.
     */
    map<U>(callbackfn: (value: T, index: number, array: T[]) => U, thisArg?: any): U[];

 

callbackfn (콜백함수) 는 세가지 인자(value, index, array)를 받음. *value 필수

 - value : 처리중인 배열 요소의 값 / index : 처리중인 배열 요소의 인덱스 / array : 메서드가 호출된 (원본)배열

 - thisArg **  : 콜백함수 내에서 'this'키워드로 사용될 객체를 명시적으로 지정. 

 - => U콜백함수가 반환할 타입.

 - U[] : 콜백 함수의 반환값. (콜백함수의 로직(조건)에 따라 새로 생성된 배열)

 

const numbers = [1, 2, 3, 4];
const strings = numbers.map((value, index) => `Number ${value} at index ${index}`);
console.log(strings); 
// 출력: ["Number 1 at index 0", "Number 2 at index 1", "Number 3 at index 2", "Number 4 at index 3"]

=> 원본 배열은 변경하지 않고, 콜백 함수가 인자로 받은 value, index에 대해 변환된 요소를 포함하는 새 배열 반환.


* thisArg 

const team = {
  members: ['Jane', 'Bill'],
  teamName: 'Super Squad',
  getTeamMembers() {
    return this.members.map(function(member) {
      return `${member} is on team ${this.teamName}`;
    }, this);  // 여기서 thisArg로 this를 전달
  }
};

console.log(team.getTeamMembers());
// 출력: ["Jane is on team Super Squad", "Bill is on team Super Squad"]

=> thisArg 로 'this'를 전달함으로서 콜백함수 내부의 'this'는 'team'의 객체를 가리키게 된다.

따라서 'this'를 통해 'team'의 객체인 'member'와 'teamName' 속성에 접근 가능

 

thisArg 를 전달하지 않은 경우. 

const team = {
  members: ['Jane', 'Bill'],
  teamName: 'Super Squad',
  getTeamMembers() {
    return this.members.map(function(member) {
      return `${member} is on team ${this.teamName}`; // TypeError: Cannot read properties of undefined (reading 'teamName')
    });  // thisArg가 없음
  }
};

console.log(team.getTeamMembers());

=> 콜백함수 내부의 'this'는 기본적으로 전역객체를 가르키거나 'undefined' (엄격모드에서)가 된다.


 

* Array.prototype.filter

/**
     * Returns the elements of an array that meet the condition specified in a callback function.
     * @param predicate A function that accepts up to three arguments. The filter method calls the predicate function one                                            time for each element in the array.
     * @param thisArg An object to which the this keyword can refer in the predicate function. If thisArg is omitted,                                                   undefined is used as the this value.
     */
    filter(predicate: (value: T, index: number, array: T[]) => unknown, thisArg?: any): T[];

 

predicate (콜백함수) 는 세가지 인자( value, index, array)를 받음.  ( * predicate 함수 : boolean값을 반환하는 함수)

 - value : 처리중인 배열 요소의 값 / index : 처리중인 배열 요소의 인덱스 / array : 메서드가 호출된 (원본)배열

 - thisArg **  : 콜백함수 내에서 'this'키워드로 사용될 객체를 명시적으로 지정. 

 - =>  unknown  : 콜백함수의 반환 타입이 true/false 이지만 타입안정성 보장을 위해 'unknown'으로 설정. 

  ( * unknown : 안전한 타입_모든 타입의 상위 타입 )

 - T[] : 콜백 함수의 반환값. (콜백함수의 로직(조건)에 따라 새로 생성된 배열)

 

const people = [
    { name: "Alice", age: 25 },
    { name: "Bob", age: 20 },
    { name: "Charlie", age: 23 }
];

const adults = people.filter(person => person.age >= 21);
console.log(adults);  
// [{ name: "Alice", age: 25 }, { name: "Charlie", age: 23 }]

=> 원본 배열은 변경하지 않고, 콜백 함수가 인자로 받은 value, index에 대해 필터링된 요소를 포함하는 새 배열 반환.

predicate함수가 true를 반환하면 해당 요소는 결과 배열에 포함되고, false를 반환하면 포함되지 않는다.

 

 

* Array.prototype.reduce

( 초기값과 배열요소값 타입이 같은 경우 'T' )

/**
     * Calls the specified callback function for all the elements in an array. The return value of the callback function is the accumulated result, and is provided as an argument in the next call to the callback function.
     * @param callbackfn A function that accepts up to four arguments. The reduce method calls the callbackfn function one time for each element in the array.
     * @param initialValue If initialValue is specified, it is used as the initial value to start the accumulation. The first call to the callbackfn function provides this value as an argument instead of an array value.
     */
    reduce(callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: T[]) => T): T;
    reduce(callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: T[]) => T, initialValue: T): T;

 

callbackfn (콜백함수) 는 네가지 인자( previousValue, currentValue, currentIndex, array)를 받음. 

 - previousValue : 초기값 / 이전 콜백 호출의 반환값

 - currentValue  : 처리중인 배열 요소의 값

 - currentIndex : 처리중인 배열 요소의 인덱스

 - array : 메서드가 호출된 (원본)배열

 - => T  : 콜백함수의 반환 타입이 true/false 이지만 타입안정성 보장을 위해 'unknown'으로 설정. 

 - initialValue: T : 초기값 (첫번째 콜백 호출에서 previousValue 로 사용), 없는 경우 배열의 첫번째 요소를 사용.

 - T : 콜백 함수의 반환값.

 

* 초기값(initialValue) 없는 경우

const numbers = [1, 2, 3, 4, 5];
const sum = numbers.reduce((previousValue, currentValue) => {
    return previousValue + currentValue;
});
console.log(sum); 
// 결과: 15

=> 초기값이 없기 때문에 배열의 첫번째 요소인 1을 초기값으로 사용. 

(배열은 최소 하나의 요소를 가져야한다. 배열이 비어있다면 'TypeError' 발생)

 

* 초기값(initialValue) 있는 경우 (동일 타입)

const factors = [2, 4, 6, 8, 10];

const product = factors.reduce((previousValue, currentValue) => {
    return previousValue * currentValue;
}, 1); // 초기값 1으로 설정

console.log(product); // 결과: 3840

=> 초기값 1부터 연산 시작. (곱셉연산이기 때문에 초기값이 0이라면 누적연산 결과가 0이된다.)

 

(빈 배열인 경우)

const numbers = [];
const sum = numbers.reduce((previousValue, currentValue) => {
    return previousValue + currentValue;
}, 0); // 초기값으로 0을 설정
console.log(sum); 
// 결과: 0

=> 배열이 비어있기 때문에 콜백함수가 호출되지 않고 초기값 0을 그대로 반환. 

 


 

( 초기값( 'U' )과 배열요소값( 'T' ) 타입이 다른 경우 )

/**
     * Calls the specified callback function for all the elements in an array. The return value of the callback function is the accumulated result, and is provided as an argument in the next call to the callback function.
     * @param callbackfn A function that accepts up to four arguments. The reduce method calls the callbackfn function one time for each element in the array.
     * @param initialValue If initialValue is specified, it is used as the initial value to start the accumulation. The first call to the callbackfn function provides this value as an argument instead of an array value.
     */
    reduce<U>(callbackfn: (previousValue: U, currentValue: T, currentIndex: number, array: T[]) => U, initialValue: U): U;

 

callbackfn (콜백함수) 는 네가지 인자( previousValue, currentValue, currentIndex, array)를 받음. 

 - previousValue : 초기값 / 이전 콜백 호출의 반환값

 - currentValue  : 처리중인 배열 요소의 값

 - currentIndex : 처리중인 배열 요소의 인덱스

 - array : 메서드가 호출된 (원본)배열

 - => U : 콜백함수의 반환 타입이 true/false 이지만 타입안정성 보장을 위해 'unknown'으로 설정. 

 - initialValue: U  : 초기값 (첫번째 콜백 호출에서 previousValue 로 사용), 없는 경우 배열의 첫번째 요소를 사용.

 -  U  : 콜백 함수의 반환값. (콜백함수의 로직(조건)에 따라 새로 생성된 배열)

 

* 초기값(initialValue) 있는 경우 (다른 타입)

(객체연산)

const items = [{price: 10}, {price: 20}, {price: 30}];
const total = items.reduce((acc, item) => acc + item.price, 0);  // 초기값 0
console.log(total);  
// 60

=> 초기값은 0 (Number), prev는 숫자(Number), 배열요소값은 객체 (Object), 연산결과는 60 (Number)

 

(문자열 누적)

const numbers = [1, 2, 3, 4, 5];

const concatenatedString = numbers.reduce((prev, curr) => prev + curr.toString(), "");
console.log(concatenatedString); 
// 결과: "12345"

=> 초기값은 "" (빈문자열_String), prev는 문자열(String), 배열요소값은 숫자(Number), 연산결과는 문자열(String)

 

(객체 누적)

const items = [
    { name: "Apple", price: 1 },
    { name: "Banana", price: 2 },
    { name: "Cherry", price: 3 }
];

const totalPrice = items.reduce((total, item) => total + item.price, 0);
console.log(totalPrice); 
// 결과: 6

=> 초기값은 0 (Number), prev(total)는 숫자(Number), 배열요소값은 객체(Object), 연산결과는 숫자(Number)

 

(객체 변환)

const products = [
    { name: "Apple", price: 1 },
    { name: "Banana", price: 2 },
    { name: "Cherry", price: 3 }
];

const productCatalog = products.reduce((catalog, product) => {
    catalog[product.name] = product.price;
    return catalog;
}, {});

console.log(productCatalog); 
// 결과: { Apple: 1, Banana: 2, Cherry: 3 }

=> 초기값은 {} (빈객체_Object), prev(catalog)는 객체(Object), 배열요소값은 객체(Object), 연산결과는 객체(Object)

 

 

** 초기값과 연산결과의 데이터 타입은 같아야함 **

 


 

[참고블로그]

https://velog.io/@jakeseo_me/%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EA%B0%9C%EB%B0%9C%EC%9E%90%EB%9D%BC%EB%A9%B4-%EC%95%8C%EC%95%84%EC%95%BC-%ED%95%A0-33%EA%B0%80%EC%A7%80-%EA%B0%9C%EB%85%90-22-%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EA%B3%A0%EC%B0%A8-%ED%95%A8%EC%88%98Higher-Order-Function-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0

 

자바스크립트 개발자라면 알아야 할 33가지 개념 #22 자바스크립트 : 자바스크립트 고차 함수(Highe

들어가기 전에 이 포스팅은 https://blog.bitsrc.io/understanding-higher-order-functions-in-javascript-75461803bad 에 있는 포스팅을 번역한 것입니다. 오역이나 의역이 있을 수 있습니다. 지적해주시면 확인 후 바로

velog.io

 


https://velog.io/@thyoondev/%EA%B3%A0%EC%B0%A8-%ED%95%A8%EC%88%98higher-order-function%EC%97%90-%EB%8C%80%ED%95%98%EC%97%AC

 

고차 함수(Higher Order Function)에 대하여

함수형 프로그래밍(functional programming)의 첫걸음

velog.io