1, 2, 3차 고차함수의 타이핑과 구현, 클로저, 클로저, 클로저...

Donghun Seol·2023년 4월 2일
0

1,2,3차 고차함수의 정의와 구현

타입스크립트에서 함수는 변수에 담긴 함수 표현식이다. 표현식 == 값 이므로 함수를 매개변수나 리턴값으로 활용할 수 있다.

어떤 함수가 단순한 값을 반환하면 1차 함수, 1차 함수를 반환하면 2차함수, 2차 함수를 반환하면 3차함수라 할 수 있다.

아래의 코드는 1,2,3차 함수의 타이핑과 구현이다.

export type FirstOrderFunc<T, R> = (arg0: T) => R;
export type SecondOrderFunc<T, R> = (arg0: T) => FirstOrderFunc<T, R>;
export type ThirdOrderFunc<T, R> = (arg0: T) => SecondOrderFunc<T, R>;

const setDefault: FirstOrderFunc<number, number> = (arg0) => {
  console.log('default value set: ', arg0);
  return arg0;
};

// add2 함수는 x라는 숫자형 매개변수를 하나만 받고, FristOrderFunc라는 타입의 1차 함수를 반환하는 함수이다.
// 반환하는 1차 함수는 y라는 숫자형 매개변수를 받고, 클로저에 있는 x와 y의 합이라는 '값'을 반환하는 1차함수 이다.
const add2: SecondOrderFunc<number, number> =
  (x: number): FirstOrderFunc<number, number> =>
  (y: number) =>
    x + y;

console.log(add2(1)(3));

// add3이라는 함수는 x라는 숫자를 매개변수로 받아서 SecondOrderFunc타입의 2차 함수를 반환하는 함수이다.
// add3에서 반환된 (익명)2차 함수는 y라는 숫자를 매개변수를 받아서 FirstOrderFunct타입의 1차 함수를 반환한다.
// 마지막으로 반환된 1차함수는 클로저에 있는 x, y, z를 모두 더한 값을 반환한다.
const add3: ThirdOrderFunc<number, number> =
  (x: number): SecondOrderFunc<number, number> =>
  (y: number): FirstOrderFunc<number, number> =>
  (z: number) =>
    x + y + z;

console.log(add3(10)(100)(1000)); // 1110

const addingToTen = add2(10); // partially applied function
console.log(addingToTen(100)); // always return sum with 10

클로저

위의 고차함수들의 몸통에서 선언되는 변수들은 항상 클로저라는 유효 범위를 가진다.
함수가 선언될시 클로저가 형성되면 자신의 유효범위 밖에 있는 변수들에 접근이 가능하다.
클로저의 메모리는 해당 변수가 평가되어 '값'을 발생시키면 해제된다.

function addSecondOrder(x : number): (number) => number {
  return function add(y: number) {
    return x + y:
  }
}

아래의 예시와 같은 클로저는 프로세스가 끝날 때 까지 지속되기도 한다.

아래 함수는 클로저를 효과적으로 사용한 아주 좋은 실용적인 예시라 생각한다.
함수형으로 작성하지 않으면 names라는 전역변수를 생성해야하는데 이를 클로저에 넣어서 오류가능성을 줄이고 실제 호출하는 부분에서는 최소한의 인터페이스만 노출했다.
만약 makeNames에 매개변수로 names를 받고, 기본매개변수를 설정한다면 더 유연하지만 오류없이 사용가능해보인다.

const makeNames = (): (() => string) => {
  const names = ['Jack', 'Jane', 'Smith'];
  let index = 0;
  return (): string => {
    if (index == names.length) index = 0;
    return names[index++];
  };
};

const makeName: () => string = makeNames();
console.log([1, 2, 3, 4, 5, 6, 7].map((n) => makeName()));
profile
I'm going from failure to failure without losing enthusiasm

0개의 댓글