클로저는 함수와 함수가 선언된 어휘적 환경의 조합이다. 클로저를 어휘적 환경이 무엇인지 알아야 하는데 무엇인가?
1. 어휘적 범위 지정(Lexical scoping)
function foo() {
var test = 'test'
function bar() {
console.log(test)
}
bar()
}
foo()
예상 하였겠지만, 'test'라는 문자열이 출력이 된다. 위의 예시는 어휘적 범위 지정(lexical scoping)의 한 예이다. 중첩된 함수는 외부 범위(scope)에서 선언한 변수에도 접근할 수 있다는 것을 알 수있다.
2. 클로저
function foo() {
var test = 'test'
function bar() {
console.log(test)
}
return bar
}
var fooOfBar = foo()
fooOfBar()
위의 코드는 어떠한가?
이것또한 예상 한것처럼 "test"문자열을 출력을 한다. 자 그렇다는 말 뜻은 foo함수가 실행 되는 동안 생성된 "test"문자열을 넣은 test변수가 foo 함수가 실행 된 이후에도 존재 한다라는 것이 된다.
자바스크립트는 함수를 리턴하고, 리턴하는 함수가 클로저를 형성하기 때문이다. 클로저는 함수와 함수가 선언된 어휘적 환경의 조합이다.
3. 간단한 활용 법
function makeAdder(x) {
return function(y) {
return x + y
}
}
var add5 = makeAdder(5)
var add10 = makeAdder(10)
console.log(add5(5))
console.log(add5(10))
console.log(add10(20))
클로저의 특성을 이용하여 위처럼 특정값에 항상 5를 더하는 함수를 만들거나 10을 더하는 함수를 만들어 낼 수 있다.
4. 간단한 활용 법 2
for (var i = 0; i < 5; i++) {
setTimeout(() => console.log(i), 0)
}
하지만 지난번 setTimeout에 대해서 설명 하였듯이 setTimeout에 입력한 함수는 바로 호출이 되는 것이 아니라 최소 시간을 기다린후 메시지큐에 넣을 뿐이고, 콜스택에 올라가 함수가 호출 되는 것은 더 이후이므로 그 동안에 i값은 상승해 있기 때문에 발생하는 문제이다.
function makeCallback(i) {
return () => {
console.log(i)
}
}
for (var i = 0; i < 5; i++) {
setTimeout(makeCallback(i), 0)
}
위와 같이 실행 방식을 클로저를 이용한 방식으로 해야 아래처럼 정상적인 값이 출력되는 것을 볼 수 있다.
추가 설명 하자면 makeCallback이 호출되는 시점에 i값은 makeCallback이 리턴하는 함수와 함께 i값이 고정된 채로 클로저가 형성되는 것이다.
5. 추가 적으로 let을 사용 하면 바로 저 문제를 해결 할 수 있다.
for (let i = 0; i < 5; i++) {
setTimeout(() => console.log(i), 10)
}
댓글
댓글 쓰기