Front-end/JavaScript

JS 클로저 5편 - Closure(함수 커링에서의 클로저 현상)

파리외 개발자 2023. 1. 16. 23:57

커링에서의 함수 생명주기

function a() {
  let grandpa = "grandpa";
  return function b() {
    let father = "father";
    return function c() {
      let son = "son";
      return `${grandpa} > ${father} > ${son}`;
    };
  };
}

a()()();

  • a함수 (변수 : grandpa, 리턴값 : 함수 b)
  • b함수 (변수 : father, 리턴값 : 함수 c)
  • c함수 (변수 : son, 리턴값 : {a함수의 변수, b함수의 변수, c함수의 변수}로 이뤄진 문자열)
  • a( ) == function b
  • a( )( ) == b( ) == function c
  • a( )( )( ) == b( )( ) == c( ) == `${grandpa} > ${father} > ${son}`
  • 여기서 function a는 함수 그 자체를, a( )는 함수가 실행된 리턴값을 의미한다.

선행되어야 할 개념

커링, VE

실행 순서

a함수가 실행되며 a함수의 실행컨텍스트에 존재하는 VE의 변수 grandpa가 콜 스택에 호출된다.

여기서 a함수는 b함수를 리턴하게 되며 b함수가 호출되며 a함수는 콜 스택에서 삭제되어야 한다.

a함수가 리턴을 하며 a의 실행컨텍스트도 삭제되고 VE에 있던 a함수의 grandpa변수도 함께 휘발된다.

하지만 위 함수에서는 b함수가 실행되며 a함수의 생명이 끝나더라도 함께 날아갔어야 할 grandpa변수는

저장공간에 남아있게 된다.

마찬가지로 b함수가 c를 리턴하며 종료되어도

b함수와 함께 끝장났어야 할 b함수의 실행컨텍스트의 VE에 존재하던 father변수 또한

grandpa와 함께 어떤 저장공간에 남아있게 된다.

그리하여 c함수는 a, b함수가 모두 종료되더라도 두 함수의 변수에 접근할 수 있게 된다.

내부의 함수가 외부의 함수의 변수를 참조하고 있는 경우 외부의 변수가 존재하던 함수가 종료되어도 가비지 콜렉터가 정리하지 않고 남아있는 현상을 클로저 현상이라 한다.
//a가 스택에서 제거
const one = a();
b();

클로저 현상은 위처럼 변수에 저장해서 자주 활용된다.

외부 함수를 first class 성질에 의거해 변수에 저장한다면,

내부 함수를 호출할 때에 one에 저장된 a의 VE환경에 접근할 수가 있다.

arrow func

const boo = (string) => (name) => (name2) =>
  console.log(`${string} ${name} ${name2}`);

boo("hi")("Kim")("See");

const booString = boo("hi");

const booStringName = booString();

중첩함수를 위처럼 화살표 함수로 나타낼 수 있다.

각각의 인자 호출단계 별로 변수에 저장을 한다면

변수에는 인자가 담겼던 상태의 함수를 그대로 저장하여 사용할 수 있으며

이것이 커링 함수이다.

내부 함수가 외부 함수의 VE를 참조하고 있을 시 외부 함수의 환경은 남아있으며, 이러한 클로저 현상을 이용해 외부 함수의 환경을 변수에 저장해 사용할 수 있다.