이번 아티클에서는 이제까지 살펴본 클로저의 기본 특성 이외에, 주의하거나 기억해야 할 예외적인 상황들에 대해서 하나씩 살펴보도록 하겠습니다.
우선, 클로저의 프로퍼티 값 - 즉 클로저가 참조하게 되는 자유 변수는 무의식적으로 '읽기'를 통한 참조만 가능하다고 생각하기 쉽습니다. 하지만 이 자유 변수는 클로저(함수)를 통해서 쓰기도 가능하다는 특징을 갖고 있습니다. 만일 클로저 함수를 반복해서 호출하여 실행할 경우에는 그 값이 바뀔 수 있다는 점을 기억해야 합니다. 예제를 통해서 살펴보겠습니다.
function outerFunc(argNum) {
var num = argNum;
return function(x) {
num += x;
console.log('num: ' + num);
}
}
var result = outerFunc(50);
result(10);
result(-35);
위 코드에서 result( )를 두 번 실행한 결과는 60, 그리고 25가 출력이 됩니다. 즉, result( )라는 함수가 호출될 때마다 참조하게 되는 자유 변수 num의 값은 result( )에서 파라미터로 전달되는 값에 따라 지속적으로 변화하게 된다는 점을 확인할 수 있습니다.
다음으로, 클로저 함수로서 반환되는 함수가 반드시 한 개로 정해져 있지 않다는 사실입니다. 예제를 통해 살펴보겠습니다.
function func() {
var a = 100;
return {
func1 : function() { console.log(++a)},
func2 : function() { console.log(-a)}
};
}
var resultObj = func();
resultObj.func1();
resultObj.func2();
실행 결과 자체는 위에서 설명한 것처럼 자유 변수를 여러번 참조하여 결과 값이 101, -101로 출력되는 것을 확인할 수 있습니다. 여기서 주목할 점은, 클로저로 사용되는 함수가 func1, func2로 익명 객체 형태로 전달되었다는 점 입니다. resultObj에서는 프로퍼티 즉, 메서드로서 func1과 func2를 호출하여 사용하는 것을 확인할 수 있습니다.
다음 예제는 setTimeout을 루프 안에서 사용할 때의 예시입니다. 원하는 결과는 1,2,3이 1초 간격으로 출력되는 것입니다.
function countSeconds(howMany) {
for(var i = 1; i <= howMany; i++) {
setTimeout(function() {
console.log(i);
}, i * 1000);
}
}
countSeconds(3);
위의 예제는 의도와 달리 4가 1초 간격으로 세 번 출력됩니다. 클로저의 관점에서, setTimeout에 전달된 익명 함수에서 i는 자유 변수가 됩니다. 하지만 실제로 이 익명 함수가 실행되는 시점은 countSeconds( ) 실행 컨텍스트가 완료된 시점이 되어버립니다.
조금 더 자세히 살펴보자면, setTimeout의 두 번째 인자인 i에서는 루프의 순서대로 1, 2, 3이 적용됩니다. 하지만 setTimeout의 첫 번째 인자로 전달되는 익명 함수는 내부 함수로서, 클로저 함수가 되어버린다고 생각해주시면 됩니다. 즉, 실행이 끝난 자유 변수를 참조하는 구조가 되어버리는 것입니다. 의도하지 않게 클로저가 되어버렸다는 것이죠. 그래서 직관적으로 이해는 잘 되지 않을 수 있지만, 이 익명 함수는 '내부 함수'로서 '실행이 끝난 자유 변수 i'를 참조하게 된다고 생각해 주시면 됩니다. 결국 console.log(i)를 출력하는 파라미터에서의 i는 결과적으로 4가 되어서 4가 계속 출력됩니다.
이 예제는 i값의 복사본과 즉시 실행 함수를 사용해 수정해야 합니다.
function countSeconds(howMany) {
for(var i = 1; i <= howMany; i++){
(function (currentI) {
setTimeout(function() {
console.log(currentI);
}, currentI * 1000);
}(i));
}
}
countSeconds(3);
'Programming > Javascript' 카테고리의 다른 글
13. Javascript 객체지향 프로그래밍(1) - 클래스 구현 2 (0) | 2022.11.30 |
---|---|
13. Javascript 객체지향 프로그래밍(1) - 클래스 구현 1 (0) | 2022.11.28 |
12. Javascript 클로저(Closure)(2) - 클로저의 활용 3 (0) | 2022.11.25 |
12. Javascript 클로저(Closure)(2) - 클로저의 활용 2 (0) | 2022.11.23 |
12. Javascript 클로저(Closure)(2) - 클로저의 활용 1 (0) | 2022.11.21 |