함수가 속한 렉스컬 스코프를 기억하여 함수가 렉시컬 스코프 밖에서 실행 될 때에도 이 스코프에 접근할 수 있게 하는 기능을 말한다.
가장 유명한 예를 보자
function foo() {
var a = 2
return function bar() {
console.log(a++)
}
}
var baz = foo()
baz() // 2
baz() // 3
baz()함수의 스코프에는 a가 있는 foo스코프 밖임에도 불구하고 우리는 baz함수를 실행하였을때 a의 값에 접근 할 수 있게 되었습니다. 이는 bar함수를 선언할때의 스코프를 baz함수에서도 접근할 수 있기 때문입니다.
클로저에 대해 처음 배우다보면 정말 생소하게 느낄 수 있다. 하지만 정말 흔히 볼 수 있다.
function wait(message) {
setTimeout(function timer(){
console.log(message)
}, 1000)
}
우리가 흔히 쓰는 setTimeout함수이다. wait함수가 실행되면 timer함수가 1초 후에 실행되는데 이때는 이미 wait의 내부 스코프는 사라져야 하지만 timer는 여전히 wait내부 스코프에 접근 가능하면 message변수를 사용할 수 있습니다.
클로저의 능력을 활용하면서 표면적으로 콜백과 상관없는 코드 패턴들이 있다. 그중 가장 강력한 패턴인 모듈을 살펴보자.
function CoolModule() {
var something = 'cool'
var another = [1,2,3]
function doSomething() {
console.log(something)
}
function doAnother() {
console.log(another.join(" ! "))
}
return {
doSomething: doSomething,
doAnother: doAnother
}
}
var foo = coolModule()
foo.domSomething(); // cool
foo.doAnother(); // 1 ! 2 ! 3
다음과 같이 모듈 패턴을 이용하면 클로저를 이용할 수 있다,.
모듈 패턴의 조건
- 하나의 최외곽 함수가 존재하고, 이 함수가 최소 한번은 호출되어야 한다.
- 최외곽 함수는 최소 한번은 하나의 내부 함수를 반환해야 한다. 그래야 해당 내부 함수가 비공개 스코프에 대한 클로저를 가져 비공개 상태에 접근하고 수정할 수 있다.