_클로저_는 JavaScript의 프로그래밍 패턴으로, 바깥쪽 렉시컬 스코프의 변수를 중첩된 코드 블록 안에서 사용할 수 있게 해줘요. JavaScript는 클로저를 자연스럽게 지원하기 때문에, 클로저가 무엇인지도 모른 채 사용하는 경우가 많아요.
// Top-level declarations are global-scope
const dozen = 12;
// Functions create a new function-scope and block-scope.
// Referencing the outer variable here is a closure.
function nDozen(n) {
return dozen * n;
}
_클로저_라는 이름은 역사적으로 λ-계산법에서 유래했으며, 함수의 열린 변수 바인딩과 닫힌 변수 바인딩을 가리키기 위해 scheme에 의해 널리 퍼졌어요 (출처).
데이터 프라이버시 / 데이터 캡슐화
// Consider this function:
const saveNumber = (number) => {
// The saved value is unaccessible by the outer lexical scope.
const value = number;
// We can provide access to the primitive value with a function, but the original will never change
return () => value;
};
// Attempting to set the variable outside of its lexical scope results in an error
value = 42;
부분 적용
// The arguments are applied one-by-one, using closures to arrive at the final result
function partialBuildUri(scheme) {
return function (domain) {
return function (path) {
return `${scheme}://${domain}/${path}`;
};
};
}
// A function could apply them all at once.
function buildUri(scheme, domain, path) {
return partialBuildUri(scheme)(domain)(path);
}
// Or apply a few to create a flexible system of functions for reuse.
function buildHttpsExercismUri(path) {
return partialBuildUri('https')('exercism.org');
}
모든 프로그래밍 언어에서 클로저는 변수 스코프와 밀접하게 관련되어 있어요. JavaScript에는 변수에 대한 렉시컬 스코프가 세 가지 있어요:
var 키워드로 함수 안에서 선언된 변수예요.let과 const 키워드로 블록({...}) 안에서 선언된 변수예요.실제로 클로저는 함수(또는 블록)가 바깥 스코프의 변수를 사용할 때 자주 생겨요. JavaScript에서는 이것이 자연스럽게 지원되기 때문에, 클로저를 특별히 의식하지 않고 사용하는 경우가 많아요.
var 키워드는 함수 스코프 변수를 정의해요. 즉, var 키워드로 정의된 변수는 그것이 정의된 함수 안 어디에서나, 그리고 중첩된 모든 렉시컬 스코프(함수든 블록이든)에서 사용할 수 있어요.
{
var five = 5;
}
// This will succeed because 'five' exists in the same scope
var tenTimes = five * 10;
let과 const 키워드는 블록 스코프 변수를 정의해요. let은 변경 가능한 변수를 정의하는데, 값이 여러 번 설정될 수 있고 정의만 하고 초기화하지 않을 수도 있어요. const는 정의할 때 반드시 초기화해야 하는 변수를 정의하며, 그 값은 이후에 바뀔 수 없어요. const 변수에 원시값을 할당하면 그 값을 변경할 수 없어요. const 변수에 _배열_이나 객체 같은 참조값을 할당하면 참조는 바뀔 수 없지만 배열의 내용은 변경할 수 있어요.
다음 블록을 살펴봐요:
// 'two' is defined at the top-level, therefore available to the global-scope
const two = 2;
{
// This succeeds, as 'two' is available from the outer lexical scope
const oneLess = two - 1;
}
// This throws an error because oneLess is not defined outside of the previous inner lexical scope
console.log(oneLess);
중괄호({...})를 사용해 블록을 마음대로 만들 수 있지만, 중괄호는 주로 if 문, 함수, _클래스_를 감쌀 때 볼 수 있어요.
const PI = 3.14;
// This function uses a closure for the value of PI (π)
function areaOfCircle(radius) {
return PI * radius * radius;
}