클로저, 실행컨텍스트 in JS

동동·2021년 8월 31일
1

클로저는 무엇인가요?

  • 클로저는 함수가 선언되었을 때의 환경을 실행시에 참조하는 함수입니다.
  • 클로저는 선언된 곳의 외부 변수를 기억하고 이에 접근할 수 있는 함수입니다. JS에서 모든 함수는 자연적으로 클로져입니다.(주1)
  • JS에서 모든 함수는 자동적으로 함수가 선언된 LexicalEnvironment를 기억하고 이를 통해 외부 변수에 접근할 수 있습니다.

주1. 하나의 예외는 new Function syntax 입니다.

어떻게 클로저가 가능한가요??

  • 모든 함수는 선언될 때, 함수 선언시의 실행 컨텍스트의 LexicalEnvironment의 참조값을 내부 프로퍼티 [[Environment]]에 저장해둡니다. [[Environement]] 참조는 한번 설정된 후 영원히 기억됩니다.

  • 함수가 실행되면, 호출 직후 로컬 변수와 함수의 매개변수를 저장하기 위해 실행 컨텍스트 및 새로운 LexicalEnvironment가 자동으로 생성됩니다.
    함수 실행시 새로 생성된 LexicalEnvironment는 함수의 [[Environment]]에 저장된 LexicalEnvironment를 외부 LexicalEnvironment로 참조합니다.

  • 코드가 변수에 접근할 때 현재 속한 실행 컨텍스트의 LexicalEnvironemnt를 먼저 찾아본 후, 변수가 존재하지 않으면 LexicalEnvironment의 외부 LexicalEnvironment를 찾으며, 최상단의 global Lexical Environment까지 이어집니다. 변수를 찾지못한다면 스트릭트 모드에서는 예외가 발생합니다.

  • 일반적으로 함수 호출이 종료되면 활성화된 실행 컨텍스트의 LexicalEnvironment는 모든 변수와 함께 메모리에서 제거됩니다. 왜냐하면 LexicalEnvironment에 대한 참조가 없기 때문이죠. 다른 자바스크립트 객체와 같이, Lexical Enviroment에 도달가능할 때만 가비지 컬렉션의 대상에서 제외됩니다.

  • 그러나 함수 호출이 종료된 후에도 여전히 해당 LexicalEnvironment에 도달 가능한 중첩 함수가 존재한다면, 이때는 이 중첩함수의 [[Environment]] 프로퍼티에 외부 함수 Lexical Environment의 참조값을 가지고 있습니다. 이 경우, 함수가 종료되더라도 LexicalEnvironment에 여전히 도달가능하므로 해당 LexicalEnvironment는 살아있게 됩니다.

  • 이론적으로는 함수가 살아있다면, LexicalEnvironment가 살아있다면 모든 외부 변수들은 살아남습니다. 하지만 실무에서는, JS엔진이 최적화를 수행합니다. JS엔진은 변수의 사용을 분석해서 외부 변수가 사용되지 않는 것이 명백하다면 해당 외부 변수는 메모리에서 제거합니다.

  • 따라서, 외부 함수가 종료되어 외부 함수의 실행 컨텍스트가 제거되어도 외부 함수의 LexicalEnvironment는 내부 함수에서 [[Environment]]를 통해 접근이 가능하므로 메모리에서 제거되지 않아, 내부 함수(클로저)를 호출시에도 함수 선언시의 환경을 참조할 수 있습니다.

Lexical Environment

  • 실행 컨텍스트는 숨겨진 내부 객체 Lexical Environment 를 가집니다. Lexical Environment는 명세에서만 이론적으로 존재하는 객체로서, 실제로 코드에서 이 객체에 접근하거나 조정할 수 없습니다.
  • Lexical Environment 는 두개의 파트로 구성되어 있습니다.
    1. Environment Record: 모든 로컬 변수를 프로퍼티로 저장하는 객체(this 값 등의 다른 정보도 저장하고 있다)
    2. outer: 함수가 선언될 때의 LexicalEnvironment에 대한 참조값

Environment Record

  • JS에서 변수는 Lexical Environment의 특별한 내부 객체인 Environment Record의 프로퍼티입니다.
  • JS엔진은 코드를 실행하기 전 실행 환경에 대한 정보를 수집하여 실행 컨텍스트와 Lexical Environment를 생성합니다.
  • Environment Record는 어떠한 식별자가 존재하는지에 대해서만 관심이 있고, 식별자의 값에는 관심이 없습니다. 따라서 최초 생성된 Environment Record의 let/const로 선언한 변수의 상태는 <unintialized> 이고, 실제로 선언되기 전까지는 접근할 수 없습니다. 이때를 흔히 Temporal Dead Zone에 변수가 존재한다고 표현합니다.
  • 함수 선언문 의 경우, Lexical Environment가 생성되면서 바로 initialized 되어 바로 사용할 수 있습니다.

https://javascript.info/closure#lexical-environment

https://humorous-octagon-753.notion.site/b1fdfd69ce0e41dfb16bab7c570972b3

https://meetup.toast.com/posts/118

https://meetup.toast.com/posts/123

profile
작은 실패, 빠른 피드백, 다시 시도

1개의 댓글

comment-user-thumbnail
2021년 9월 5일

JS에서 모든 함수는 자연적으로 클로져입니다. 이 말이 이해되는 날이 오네요. 좋은 정리 감사합니다. 👍

답글 달기