함수와 그 함수가 선언된 렉시컬 환경과의 조합
function makeCounter(predicate) {
// 카운트 상태를 유지하기 위한 자유 변수
var counter = 0;
// 클로저를 반환
return function () {
counter = predicate(counter);
return counter;
};
}
// 보조 함수
function increase(n) {
return ++n;
}
// 보조 함수
function decrease(n) {
return --n;
}
// 함수로 함수를 생성한다.
// makeCounter 함수는 보조 함수를 인자로 전달받아 함수를 반환한다
const increaser = makeCounter(increase);
console.log(increaser()); // 1
console.log(increaser()); // 2
// increaser 함수와는 별개의 독립된 렉시컬 환경을 갖기 때문에 카운터 상태가 연동하지 않는다.
const decreaser = makeCounter(decrease);
console.log(decreaser()); // -1
console.log(decreaser()); // -2
함수를 어디에서 정의했는지에 따라 상위 스코프를 결정한다. 이를 렉시컬 스코프(정적 스코프)라 한다.
==
detail : 렉시컬 환경의 "외부 렉시컬 환경에 대한 참조"에 저잘할 참조값, 즉 상위 스코프에 대한 참조는 함수 정의가 평가되는 시점에 함수가 정의된 환경에 의해 결정된다. 이것이 렉시컬 스코프이다.
함수는 자신의 내부 슬롯 [[Environment]]에 자신이 정의된 환경, 즉 상위 스코프의 참조를 저장한다.
외부 함수보다 중첩 함수가 더 오래 유지되는 경우 중첩 함수는 이미 생명 주기가 종료한 외부 함수의 변수를 참조할수 있다. 이런 중첩 함수를 클로저라 부른다.
외부함수의 실행 컨텍스트가 종료되더라도 out 함수의 렉시컬 환경은 inner 함수의 [[environment]]내부 슬롯에 의해 참조되고 있고, inner 함수가 전역 변수에 의해 참조되고 있다면 가비지 컬렉션의 대상이 되지 않는다.
클로저는 중첩 함수가 상위 스코프의 식별자를 참조하고 있고 중첩 함수가 외부 함수보다 더 오래 유지되는 경우에 한정하는 것이 일반적.
클로저에 의해 참조되는 상위 스코프의 변수를 자유 변수(free variable)이라 부른다.
(closure -> 자유 변수에 대해 닫혀있음을 뜻함)
상태를 안전하게 변경하고 유지하기 위해 사용한다.
즉, 상태를 안전하게 은닉(information hiding)하고 특정 함수에게만 상태 변경을 허용하기 위해 사용.
const increase = (function () {
let num = 0;
return function () {
return ++num;
}
}())
Javascript는 public, private, protected 같은 접근 제한자를 제공하지 않기 때문에, 완벽한 정보 은닉을 지원하지 않는다.
2021년 기준 클래스에 private 필드를 정의할 수 있는 표준 사양이 제안되어 있다.