본문 바로가기

JavaScript/모던 자바스크립트 딥다이브

[Modern JavaScript Deep Dive] closure

클로저는 함수를 일급 객체로 취급하는 함수형 프로그래밍 언어 (예: 하스켈, 리스프, 얼랭, 스칼라등)에서 사용되는 중요한 특성이다. 클로저는 자바스크립트 고유의 개념이 아니므로 글로저의 정의가 ECMAScript 사양에 등장하지 않는다.

MDN 에서는 클로저를 다음과 같이 정의한다.

A closure is the combination of a function and the lexical enviroment within which that function was delared.
클로저는 함수와 그 함수가 선언된 렉시컬 환경과의 조합이다.

const x = 1;
function outerFunc() {
    const x = 10;
      function innerFunc() {
        console.log(x); // 10
    }
      innerFunc();
}
outerFunc();

 

위 예제에서 중첩함수 innerFunc의 상위 스코프는 외부함수 outerFunc의 스코프이다. 따라서 중첩함수 innerFunc 내부에서 자신을 포함하고 있는 외부 함수 outerFunc의 x 변수에 접근할 수 있다.

만약 innerFunc 가 outerFunc 함수의 내부에서 정의된 중첩함수가 아니라면 innerFunc 함수를 outerFunc 함수의 내부에서 호출한다 하더라도 outerFunc함수의 변수에 접근할 수 없다. (아래 예시)

 

const x = 1;
function outerFunc() {
    const x = 10;
      innerFunc();
}
function innerFunc() {
     console.log(x); // 1 
}
outerFunc();

렉시컬 스코프는 뭘까? 자바스크립트 엔진은 함수를 어디서 호출했는지가 아니라 함수를 어디에 정의했는지에 따라 상위 스코프를 결정한다. 이를 렉시컬 스코프(정적 스코프)라 한다.

✅ 함수의 상위 스코프는 함수를 어디서 정의했느냐에 따라 결정된다.

✅ 스코프의 실체는 실행 컨텍스트의 렉시컬 환경이다. 이 렉시컬 환경은 자신의 외부 렉시컬 환경에 대한 참조를 통해 상위 렉시컬 환경과 연결된다. -> scope chain

✅ 렉시컬 환경의 "외부 렉시컬 환경에 대한 참조"에 저장할 참조값, 즉 상위 스코프에 대한 참조는 함수 정의가 평가되는 시점에 함수가 정의된 환경(위치)에 의해 결정된다. 이것이 바로 렉시컬 스코프이다.

함수가 정의된 환경과 호출되는 환경은 다를 수 있다. 따라서 렉시컬 스코프가 가능하려면 함수는 자신이 호출되는 환경과는 상관없이 자신이 정의된 환경, 즉 상위 스코프(함수 정의가 위치하는 스코프가 바로 상위 스코프)를 기억해야한다.

✅ 함수는 자신의 내부 슬롯\[[Environment]]에 자신이 정의된 환경, 즉 상위 스코프의 참조를 저장한다.

함수 정의가 평가되어 함수 객체를 생성할 때 자신이 정의된 환경(위치)에 의해 결정된 상위 스코프의 참조를 함수 객체 자신의 내부 슬롯에 저장한다.

함수 내부에서 정의된 함수 표현식은 외부 함수 코드가 실행되는 시점에 평가되어 함수 객체를 생성한다. 이 때 생성된 함수 객체의 내부 슬롯에는 함수 정의가 실행되는 시점, 즉 외부 함수 코드 실행 시점에 실행 중인 실행 컨텍스트의 렉시컬 환경인 외부 함수 렉시컬 환경의 참조가 저장된다.

✅ 함수 객체의 내부 슬롯 [[Environment]]에 저장된 현재 실행중인 실행 컨텍스트의 렉시컬 환경의 참조가 바로 상위 스코프이다.또한 자신이 호출되었을 때 생성될 함수 렉시컬 환경의 "외부 렉시컬 환경에 대한 참조"에 저장될 참조값이다. 함수 객체는 내부 슬롯에 저장한 렉시컬 환경의 참조, 즉 상위 스코프를 자신이 존재하는 한 기억한다.

함수 코드의 평가 순서는 다음과 같다.

  1. 함수 실행 컨텍스트 생성
  2. 함수 렉시컬 환경 생성
    2-1. 함수 환경 레코드 생성 (변수)
    2-2. this 바인딩
    2-3. 외부 렉시컬 환경에 대한 참조 설정

this 는 현재 실행되는 코드의 실행 컨텍스트를 말합니다.