클로저는 내부 함수가 외부 함수에 접근할 수 있는 함수를 의미한다. 함수와 함수가 선언된 어휘적 환경(lexical environment)의 조합을 통해 만들어진다. 함수를 어디서 정의했는지에 따라 상위 스코프를 결정하고 중첩된 함수는 외부 함수 스코프를 상위 스코프로 포함하고 있기 때문에 내부 함수는 외부 함수의 변수의 접근할 수 있다.[1] 반대로 외부 함수에서 내부 함수로 접근하는 것은 불가능하다. 클로저는 자바스크립트에서 중요한 개념이다. 클로저를 사용하면 특정한 상태를 기억하고 값을 은닉할 수 있고, 클로저를 활용하여 모듈 패턴을 정의할 수 있다.
<aside> 💡 "lexical"이란, 어휘적 범위 지정(lexical scoping) 과정에서 변수가 어디에서 사용 가능한지 알기 위해 그 변수가 소스코드 내 어디에서 선언되었는지 고려한다는 것을 의미한다. 단어 "lexical"은 이런 사실을 나타낸다. 중첩된 함수는 외부 함수 범위(scope)에서 선언한 변수에 내부 함수가 접근할 수 있다. [1]
</aside>
자바스크립트 엔진은 함수 호출 위치가 아니라 함수 정의 위치에 따라 상위 스코프를 결정한다.
함수는 생성되는 시점에서 자신의 내부 슬롯에 자신이 정의된 환경의 상위 스코프 참조를 저장한다. 함수에서 변수에 접근할 때 함수 안에서 변수를 찾지 못하면 상위 스코프로 확장해서 찾는다. 중첩된 함수는 외부 함수 스코프를 내부 슬롯에 저장한다.
const a = 10;
function fn() {
const a = 5;
fnA();
// 함수의 호출 위치와 상위 스코프는 관계가 없다.
}
function fnA () {
console.log(a);
// fnA의 상위 스코프는 전역 렉시컬 환경을 내부슬롯에 저장한다.
}
fn(); // 10
fnA(); // 10
아래 예제와 비교해보자.
const a = 10;
function fn() {
const a = 5;
function fnA () {
console.log(a);
}
fnA();
}
fn(); // 5
아래 사이트에서 어떻게 10을 출력하지 않고 5를 출력하는지 확인해보자.
JavaScript Tutor - Visualize JavaScript code execution to learn JavaScript online