JS | 클로저(Closure) 와 호이스팅
클로저란?
클로저란 함수와 렉시컬 환경의 조합으로 함수가 생성될 당시의 외부 변수를 기억하고 생성된 이후에도 계속 접근이 가능한 것을 의미한다.
클로저를 이해하기 위한 사전 지식
1. 실행 컨텍스트 (Execution Context)
실행 컨텍스트는 코드를 실행하는데 필요한 환경을 제공하는 객체이다. 자바스크립트 코드가 실행되면 자바스크립트 엔진은 콜스택에 전역 실행 컨텍스트를 담고, 코드를 한줄씩 읽어나가며 코드가 선언되었을때의 환경을 실행컨텍스트에 저장하게 된다.
이 과정은 생성 단계(Creation Phase) 와 실행 단계(Execution Phase) 를 거치면서 이루어지는데, 생성단계에서는 실행 컨텍스트를 생성하고 선언문 코드만 실행하여 환경 레코드(Environment Record)에 기록한다. 선언문의 기록이 끝나면 실행단계로 넘어가서 선언문 외의 코드들이 순차적으로 실행된다.
2. 렉시컬 환경
렉시컬 환경이란 코드를 실행하기에 앞서 실행할 스코프 범위 안에 있는 변수와 함수를 프로퍼티로 저장하는 객체이다.
자바스크립트에서는 실행컨텍스트를 통해 이 렉시컬 환경을 관리한다. 렉시컬 환경에는 환경 레코드(Environment Record) 와 외부환경(Outer Environment)객체가 있는데 환경 레코드는 선언된 변수들을 프로퍼티 객체로 저장하고 있으며 Outer Environment 객체에는 외부 코드와 연관된 외부 렉시컬 환경에 대한 참조가 저장되어 있다.
💡 클로저 - 코드가 실행되면 필요한 변수를 해당 로컬 스코프의 환경 레코드에서 찾고, 없다면 외부 렉시컬 환경이 참조하고 있는 스코프의 환경 레코드에서 찾는다. 이런 식으로 코드가 실행되는 스코프 바깥에서도 선언된 변수에 접근이 가능한 것
* 스코프는 변수가 접근할 수 있는 영역을 의미한다.
호이스팅이란?
호이스팅과 관련하여 오해가 2가지 있다.
1. 호이스팅은 코드가 최상단으로 끌어올려지는 것이다.
2. var 는 호이스팅이 되고 let, const는 호이스팅이 되지 않는다.
위 2가지 모두 틀린 문장이다.
var 은 함수 스코프, let과 const 는 블록 스코프이다. 클로저에서 설명했듯이 실행 컨텍스트 생성단계에서 JS엔진 전체 코드를 한번 훑으며 선언문 코드를 우선적으로 환경 레코드에 저장한다. var, let, const 모두 우선적으로 환경 레코드에 저장된다. 하지만 var 는 선언과 동시에 undefined 값으로 초기화가 이루어진다. 따라서 선언 되기 전에 호출이 되어도 환경 레코드에서 초기화된 undefined 값을 참조할 수 있다. 반면 let 과 const는 환경 레코드에 선언 되고 uninitialized 라는 상태로 초기화 된다. uninitialized는 undefined와 달리 참조할 수 없다. 따라서 값을 읽어올 수 없으므로 ReferenceError가 발생한다.
💡 호이스팅 - 코드가 실행되기 전 실행 컨텍스트를 생성할 때 선언문을 우선적으로 환경레코드에 저장하면서 마치 아래에 있는 선언문 코드들이 위에서 실행된 것처럼 동작하는 것