[TIL] #12 (2022.01.31)

어느 개발자·2022년 1월 31일
0

TIL

목록 보기
12/15
post-thumbnail

클로저(Closure)에 대해 알아보자!

✍️ 출처
본 포스팅은 모던 자바스크립트 Deep Dive를 읽고 정리한 글입니다.

클로저의 정의

클로저(Closure)는 자바스크립트의 고유 개념이 아니다. 함수를 일급 객체 로 취급하는 함수형 프로그래밍 언어에서 사용되는 중요한 특성이다.

클로저는 자바스크립트 고유 개념이 아니므로 클로저의 정의가 ECMAScript 사양에 등장하지 않는다. MDN에서는 클로저에 대해 다음과 같이 정의하고 있다.

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

🤔 정의부터 난해하지만.. 정의부터 이해해보자!

정의부터 이해해보자!

렉시컬 스코프

클로저의 정의에서 가장 먼저 이해해야 할 핵심 키워드는 함수가 선언된 렉시컬 환경이다.
이와 관련된 개념인 렉시컬 스코프에 대해 알아보자.

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

const x = 1;

function foo() {
    const x = 10;
    bar();
}

function bar() {
    console.log(x);
}

foo(); // 어떤 값이 출력될까?
bar(); // 어떤 값이 출력될까?

foo 함수와 bar 함수는 모두 전역에서 정의된 전역 함수이다. 함수의 상위 스코프는 함수를 어디서 정의했느냐에 따라 결정되므로 foo 함수와 bar 함수의 상위 스코프는 전역이다. 함수를 어디서 호출하는지는 함수의 상위 스코프 결정에 어떠한 영향도 주지 못한다.

즉, 함수의 상위 스코프는 함수를 정의한 위치에 의해 정적으로 결정되고 변하지 않는다.


예시를 하나 더 살펴보자.

const x = 1;

function outerFunc() {
    const x = 10;

    function innerFunc() {
        console.log(x); // 10
    }

    innerFunc();
}

outerFunc();

결과 10을 출력한다.

outerFunc 함수 내부에서 중첩 함수 innerFunc 가 정의되고 호출되었다. 이때 innerFunc 의 상위 스코프는 함수 outerFunc 의 스코프이다. 따라서 innerFunc 는 상위 스코프인outerFuncx 변수에 접근할 수 있는 것이다.

const x = 1;

function outerFunc() {
    const x = 10;
    innerFunc();
}

function innerFunc() {
    console.log(x); // 1
}

outerFunc();

결과 1을 출력한다.

innerFunc 의 상위 스코프는 전역이므로 1을 출력한다! 첫 번째 예시와 동일하다.


스코프의 실체는 실행 컨텍스트의 렉시컬 환경이다. 이 렉시컬 환경은 자신의 외부 렉시컬 환경에 대한 참조(Outer Lexcial Enviromnent Reference)를 통해 상위 렉시컬 환경과 연결된다. 이것이 바로 스코프 체인이다.

따라서 함수의 상위 스코프를 결정한다는 것은 렉시컬 환경의 외부 렉시컬 환경에 대한 참조에 저장할 참조값을 결정한다는 것과 같다. 렉시컬 환경의 외부 렉시컬 환경에 대한 참조에 저장할 참조값이 바로 상위 렉시컬 환경에 대한 참조이며, 이것이 상위 스코프이기 때문이다. 이 개념을 반영해서 다시 렉시컬 스코프를 정의해보면 다음과 같다.

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

0개의 댓글