클로져는 자바스크립트 뿐만 아니라 함수를 일급 객체로 취급하는 함수형 프로그래밍 언어에서 사용되는 개념이다. 클로져를 좀 더 쉽게 이해하기 위해서는 실행 컨텍스트를 이해하는 것이 중요하다고 생각한다.
클로져의 개념과 특징을 알아보자.
함수 객체의 Environment
자바스크립트 엔진은 함수가 어디에서 호출되었는지가 아니라 함수가 어디에서 정의되었는지에 따라 상위 스코프를 결정하게 된다. 그리고 상위 스코프를 함수 객체의 내부 슬롯인 Evironment은 현재 실행 중인 실행 컨텍스트의 렉시컬 환경을 참조한다.
다음 코드를 보자 전역 코드가 평가되는 과정에서 apple 함수는 전역 환경에서 정의되었기 때문에 apple함수의 Evironment는 전역 렉시컬 환경을 참조하게 된다.
const a = 1;
function apple() {
console.log('apple');
}
apple();
그렇다면 클로져는 무엇일까?
다음의 코드를 보자. 전역에 apple 함수를 정의하였고 apple 함수 내에는 banana 함수를 반환하고 있으며 banana함수는 변수 a의 값을 변경하여 출력한다.
전역에서 apple함수를 banana2라는 변수에 할당한 후에 콜 스택에서 제거된다. 그렇다면 banana2의 실행결과는 어떻게 될까? banana2 함수는 변수 a의 값인 'banana'를 출력하게 된다.
const a = 1;
function apple() {
let a = 'apple';
const banana = () => {
a = 'banana';
console.log(a);
}
return banana
}
const banana2 = apple();
banana2();
apple함수가 콜 스택에서 제거되었는데 어떻게 banana 함수는 apple 함수의 변수 a에 접근할 수 있었을까? 그것은 함수 객체의 내부 슬롯인 Evironment 덕분이다. 현재 apple 함수의 내부에 banana 함수가 정의되었으며 Evironment가 apple을 참조하고 있다. 즉 banana 함수는 외부 렉시컬 환경 참조를 apple로 하게된다.
apple 함수를 banana2에 할당하고 콜 스택에서 제거되지만 여전히 banana2는 apple을 가리키고 있어 변수 a에 접근하고 출력할 수 있다. 또한 apple이 콜 스택에서 제거되었다고 가비지 컬렉터가 apple에 대한 메모리 공간을 해제하지 않는다. 아직 banana2가 apple을 참조하고 있기 때문이다.
이처럼 외부함수보다 그 안의 중첩함수의 생명 주기가 더 오래 유지되는 함수를 클로져라고 한다.
생명 주기가 오래유지된다고 모든 함수가 클로져는 아니다
다음 코드는 클로져에 해당될까? 위의 클로져 예시에서 본 코드와 유사하다. 하지만 banana함수는 내부에서 정의한 변수인 b에 'banana'를 할당하고 이를 출력하고 있다. 즉 banana함수는 apple 함수의 변수를 참조하고있지 않다.
const a = 1;
function apple() {
let a = 'apple';
const banana = () => {
let b = 'banana';
console.log(b);
}
return banana
}
const banana2 = apple();
banana2();
위의 코드는 클로져가 아니다. apple 함수가 콜 스택에서 제거된 후에 banana 함수는 apple 함수의 변수를 참조하고 있지 않다. 따라서 apple 함수는 어떠한 곳에서도 참조하고있지 않기 때문에 가비지 콜렉터에 의해 메모리가 해제된다.
클로져는 두 가지 조건에 해당되어야 한다.
1. 중첩 함수가 상위 스코프의 식별자를 참조하고 있어야한다.
2. 중첩 함수가 외부 함수보다 생명주기가 더 오래 유지되어야 한다.
위의 두 조건에 맞는 중첩 함수가 클로져가 된다.
'프로그래밍 > JavaScript' 카테고리의 다른 글
[JS] 브라우저의 렌더링 과정 (0) | 2021.08.03 |
---|---|
[JS] 함수 (0) | 2021.07.19 |
[JS] 실행 컨텍스트 (0) | 2021.07.07 |
[JS] 호이스팅이 발생하는 이유 (0) | 2021.07.06 |
[Vue] 싱글 파일 컴포넌트(SFC) (0) | 2021.05.11 |