const x = 1;
function outerFunc() {
const x = 10;
function innerFunc() {
console.log(x); // 10
}// innerFunc과 outerFunc 사이는 클로저
innerFunc();
} // outerFunc과 전역컨텍스트 사이의 클로저
outerFunc();
클로저는 내부 함수로부터 외부함수에의 접근 권한을 주며 이론적으로는 함수 생성 시점에 언제나 생긴다.
const x = 1;
function foo() {
const x = 10;
bar();
}
function bar() {
console.log(x);
}
foo(); // 1
bar(); // 1
자바 스크립트 엔진은 함수를 어디서 호출했는지가 아니라 함수를 어디에 정의했는지에 따라 상위 스코프를 결정한다. 이를 렉시컬 스코프라 한다.
const x = 1;
function foo() {
const x = 10;
bar();
}
function bar() {
console.log(x);
}
foo(); // 1
bar(); // 1
함수는 자신의 내부 슬롯 [[Environment]]에 작신이 정의된 환경, 즉 상위 스코프의 참조를 저장한다.
const x = 1;
// ①
function outer() {
const x = 10;
const inner = function () { console.log(x); }; // ②
return inner;
}
// outer 함수를 호출하면 중첩 함수 inner를 반환한다.
// 그리고 outer 함수의 실행 컨텍스트는 실행 컨텍스트 스택에서 팝되어 제거된다.
const innerFunc = outer(); // ③ -> inner
innerFunc(); // ④ 10
외부 함수보다 중첩 함수가 더 오래 유지되는 경우 중첩 함수는 이미 생명주기가 종료한 외부 함수의 변수를 참조할 수 있다. 이러한 중첩 함수를 클로저라고 한다.
// 카운트 상태 변수
let num = 0;
// 카운트 상태 변경 함수
const increase = function () {
// 카운트 상태를 1만큼 증가 시킨다.
return ++num;
};
console.log(increase()); // 1
console.log(increase()); // 2
console.log(increase()); // 3
위의 예시의 카운트 상태는 전역 변수를 통해 관리되고 있기때문에 언제든지 누구나 접근할 수 있다.
이는 오류를 발생시킬 가능성이 있는 좋지 않은 코드다
// 카운트 상태 변경 함수
const increase = (function () {
// 카운트 상태 변수
let num = 0;
// 클로저
return function () {
// 카운트 상태를 1만큼 증가 시킨다.
return ++num;
};
}());
console.log(increase()); // 1
console.log(increase()); // 2
console.log(increase()); // 3