클로저

1Hoit·2023년 1월 4일
0

자바스크립트

목록 보기
10/25

들어가기전...

내 생각으로는
클로저를 이해하기 전 스코프실행컨텍스트 개념이 선행 된다면 클로저를 이해하기 편할 것 같다.

클로저란?

정의 : 클로저는 함수와 그 함수가 선언된 렉시컬 환경과의 조합이다. (출처: mdn)

이렇게만 보니 처음에는 이게 무슨 말인가 했다.
하지만 계속 찾아보고 알아보니 핵심이 있었다.

핵심 : 함수가 선언된 렉시컬 환경!!


클로저를 사용하는 목적은 무엇일까?
상태를 안전하게 변경하고 유지하기 위해 사용한다. 즉, 상태를 안전하게 은닉하고 특정 함수에만 상태 변경을 허용하기 위해 사용한다.
이러한 목적으로 클로저를 사용하면 의도치 않은 상태 변경을 막을 수 있다.
그러므로 우리는 클로저를 통해 불필요한 전역 변수 사용을 줄이고, 스코프를 이용해 값을 보다 안전하게 다룰 수 있다.


클로저를 쉽게 풀어서 생각해보자

내가 이해한 바로 설명을 적으려고 한다.

클로저는 함수를 반환하는 함수이다!
또한 외부함수와 내부함수로 이루어졌고 내부함수는 외부함수의 변수에 접근이 가능하다!

일반함수 vs 클로저

  • 일반함수는 함수 실행이 끝나고 나면 함수 내부의 변수를 사용할 수 없다.
  • 클로저는 외부 함수의 실행이 끝나더라도 외부 함수 내 변수가 메모리 상에 저장된다. (외부함수의 렉시컬 환경을 메모리에 저장하기 때문)
    --> 이부분은 실행컨텍스트와 스코프 개념이 있다면 이해하기 편하다.
    간략하게 설명하자면 JS엔진은 함수를 어디서 호술했는지가 아니라 함수를 어디에 정의했는지에 따라 상위 스코프가 결정된다

클로저의 조건

그렇다면 중첩된 모든 함수는 클로저인 것인가?
아니다!!

  • 아무리 중첩된 함수여도 상위 스코프의 어떠한 식별자도 참조하지 않는 함수는 클로저가 아니다.
  • 즉, 중첩 함수가 상위 스코프의 식별자를 참고하고 있고 중첩 함수가 외부 함수보다 더 오래 유지되는 경우에 한정된다.

예를 들어보자

const x = 1;

function outer(){  // 1번
  const x = 10;
  const inner = function () { console.log(x) }; // 2번
  return inner;
}

// outer 함수를 호출하면 중첩함수 inner를 반환한다.
// 그리고 outer 함수의 실행 컨텍스트는 실행 컨텍스트 스택에서 pop 된다.
const innerFunc = outer(); // 3번
innerFunc(); // 4번 , 10

위 코드를 보면 outer 함수를 호출(3번)하면 outer 함수는 중첩함수 inner를 반환하고 생명주기가 끝난다. 즉, outer함수의 실행이 종료되면 outer함수의 실행 컨텍스트는 실행컨텍스트 스택에서 제거된다.
그런데 4번을 보게 되면 10이라는 값을 반환한다. 이는 outer함수의 지역 변수 x인 값이다.
이렇게 외부 함수보다 중첩함수가 더 오래 유지되는 경우 중첩함수는 생명주기가 끝난 외부함수의 변수를 참조할 수 있다 (클로저의 조건)
조금 더 쉽게 말하자면 outer 함수의 실행 컨텍스트가 실행컨텍스트 스택에서 제거되지만 outer 함수의 렉시컬 환경까지 소멸하지 않기 때문에 위와 같이 클로저로서 동작할 수 있는 것이다.
(outer 함수의 렉시컬 환경이 inner 함수의 내부 슬롯에 의해 참조되고 있고 inner 함수는 전역변수 innerFunc에 의해 참조되고 있으므로 가비지컬렉션의 대상이 되지 않기 때문.)
(-> 참고로 가비지 컬렉터는 참조되고 있는 메모리 공간을 함부로 해제하지 않는다.)

그림으로 이해해보기

1. 전역 함수 객체의 상위 스코프 결정 과정

2. 중첩 함수의 상위 스코프 결정 과정

3. outer 함수의 실행 컨텍스트 제거, 하지만 outer 함수의 렉시컬 환경은 유지

4. 외부 함수가 소멸해도 반환된 중첩 함수는 외부 함수의 변수를 참조할 수 있다.


출처 및 참고 - 모던 자바스크립트 Deep Dive (이응모)

profile
프론트엔드 개발자를 꿈꾸는 원호잇!

0개의 댓글