자바스크립트 심화 개념! 하면 대표적으로 '클로저'가 떠오른다.
클로저란 무엇일까?

MDN에 클로저가 무엇인지 검색을 해보면, 다음과 같이 설명되고 있다.

주변 상태에 대한 참조와 함께 묶인 함수의 조합.
내부 함수에서 외부 함수의 범위에 대한 접근을 제공.
위의 설명이 잘 와닿지 않으니, 조금 더 자세하게 살펴보자..!
(실행 컨텍스트에 대해 잘 모르시는 분들은 이전 포스트를 먼저 읽어주세요🧐)
코드의 실행 과정
클로저는 자바스크립트 엔진이 아래의 코드를 실행하는 과정을 살펴보면서 이해할 수 있다.
let name = '개구리';
function makeFunc() {
let name = '고양이';
function displayName() {
console.log(name);
}
return displayName;
}
let myFunc = makeFunc();
myFunc();
먼저 위의 코드를 실행하면, 이렇게 아래의 그림과 같이 전역 실행 컨텍스트가 생성되고,
선언문들을 읽어서 다음과 같이 렉시컬 환경의 환경 레코드에 저장한다.

그다음으로는, makeFunc 함수가 호출이 되어, makeFunc 함수 실행 컨텍스트가 실행된다.
아래의 그림으로 나타낼 수 있다. 마찬가지로, 아래의 그림처럼 함수 내부의 선언문들도 환경 레코드에 저장해 주자.

그리고, 해당 함수는 displayName 함수를 반환한다. 그렇기 때문에 myFunc 변수에는 displayName 함수가 저장이 된다.
displayName 함수가 반환되면, makeFunc 함수 실행 컨텍스트도 종료된다. 아래의 그림처럼 말이다.

이제 myFunc 변수에 담긴 displayName 함수가 실행된다.
함수가 실행되면 함수 실행 컨텍스트가 생성되고, displayName 함수 내부의 console.log가 실행되는데,
displayName 함수 실행 컨텍스트에는 출력하고자 하는 값인 name 변수가 존재하지 않는다.
따라서 외부 환경 참조를 통해 상위 렉시컬 환경을 참조해야 하는데,
현재 makeFunc 함수 실행 컨텍스트는 종료된 상황이니, 아래의 그림처럼
이렇게 우선 전역 실행 컨텍스트의 환경을 참조해 보자.

그럼 console.log(name)을 출력하면 '개구리'가 출력이 될 것 같다.
실제로 코드를 실행하면 어떤 값이 출력되는지 아래의 그림을 통해 살펴보자.

'개구리'가 아닌 '고양이'가 출력이 된다.
name 변수를 출력했을 때 '고양이'라는 값이 출력되려면,
앞서 봤던 그림처럼 displayName의 외부환경 참조는, 이미 종료된 makeFunc 함수 환경을 참조해야 한다.
굉장히 이상하다고 느낄 수 있다. 이러한 현상이 바로 '클로저'와 연관되어 있다.
렉시컬 스코프, 내부 슬롯
자바스크립트의 식별자들은 자신이 선언된 위치에 따라 스코프를 결정하는 방법인 렉시컬 스코프를 따른다.
즉, 자신의 스코프를 결정하기 위해 자신이 어디에 선언되어 있는지에 대한 정보를 알고 있어야 한다는 말이다.
하지만, 이 실행 컨텍스트에는 식별자의 선언 위치에 대한 정보는 하나도 없다.
이렇게 함수가 자신이 선언된 위치를 기억하는 공간을 '내부 슬롯'이라고 부른다.

그리고 자바스크립트에서 실행 컨텍스트 내부의 외부 환경 참조는 이 내부 슬롯을 참조해 값을 저장한다.
다시 코드로 돌아와서 살펴보면, 전역 실행 컨텍스트에 있는 makeFunc 함수의 내부 슬롯에는,
makeFunc 함수의 상위 스코프인 전역 렉시컬 환경이,
그리고 makeFunc 함수 실행 컨텍스트에 저장된 displayName 함수의 내부 슬롯에는,
상위 스코프인 makeFunc 함수 렉시컬 환경이 저장되어 있다.
즉, 내부 슬롯에 저장된 랙시컬 환경이 자신에게 접근할 수 있는 범위라는 말이다.
아래의 그림으로 확인해 보면 쉽게 이해할 수 있다.

그다음으로는 makeFunc 함수 실행 컨텍스트가 종료되었고,
아래의 그림처럼 displayName 함수 실행 컨텍스트가 생성됐다.

그럼, 이 displayName 함수 실행 컨텍스트의 외부 환경 참조는,
전역 실행 컨텍스트의 환경 레코드를 참조하는 것이 아니라,
내부 슬롯에 저장되어 있는 자신의 상위 렉시컬 환경을 참조한다.
이렇게 실행 컨텍스트의 외부 환경 참조는 '내부 슬롯'에 저장되어 있는 값을 참조해 값을 저장한다.
따라서 우리가 출력하고자 했던 name 변수에는 '개구리'라는 값이 아니라,
이렇게 아래의 그림처럼 '고양이'라는 값이 저장되어, 코드 실행 결과 '고양이'가 출력된다.

여기서 이 displayName이 바로 클로저다.
정의
클로저를 한 문장으로 정리해 보면,
displayName 함수처럼 자신의 외부에 있는 makeFunc 함수가 종료되었음에도 불구하고,
displayName 함수가 이 외부 함수가 가지고 있는 변수를 참조할 수 있는 상황에서, 내부 함수가 바로 클로저인 것이다.
즉, 내부 함수가 외부 함수보다 오래 유지되어 외부 함수는 종료되었지만,
내부 함수가 여전히 외부 함수의 스코프에 접근할 수 있는 상황에서 이 내부 함수를 '클로저'라고 부른다.
'javascript' 카테고리의 다른 글
HTML, CSS, Javascript로 크롬 시작화면 개발하기 (2) | 2024.09.24 |
---|---|
화살표 모양 함수는 뭐가 다를까? (2) | 2024.09.11 |
함수 호출 방법에 따라 달라지는 this (0) | 2024.08.14 |
SPA와 history api (0) | 2024.08.11 |
자바스크립트로 상태 관리하기 (0) | 2024.07.31 |