Study/JavaScript

[클로저] 클로저를 활용할 때 주의사항

AC 2019. 6. 16. 12:45

클로저는 자바스크립트의 강력한 기능이지만, 너무 남발하여 사용하면 안 된다. 여기서는 클로저에서 사용자가 쉽게 간과할 수 있는 사항을 정리했다.

 

 

클로저의 프로퍼티값이 쓰기 가능하므로 그 값이 여러 번 호출로 항상 변할 수 있음에 유의해야 한다.

 

function outerFunc(argNum){
	var num = argNum;
    return function(x) {
    	num += x;
        console.log('num: ' + num);
        }
}
var exam = outerFunc(40);
exam(5);
exam(-10);

위 코드에서 보는 바와 같이 exam 값을 호출할 때마다, 자유 변수 num의 값은 계속해서 변화하니 주의해야 한다.

 

function func() {
	var x = 1;
    return {
    	func1 : function() { console.log(++x); },
        func2 : function() { console.log(-x); }
    };
};

var exam = func();
exam.func1();
exam.func2();

위 코드에서는 반환되는 객체에는 두 개의 함수가 정의되어 있는데, 두 함수 모두 자유 변수 x를 참조한다.

그리고 각각의 함수가 호출될 때마다 x 값이 변화하므로 유의해야 한다.

 

루프 안에서 클로저 활용할 때는 주의하자.

 

function countSeconds(howMany) {
	for (var i = 1; i<=howMany; i++) {
    	setTimeout(function() {
        	console.log(i);
        }, i*1000);
    }
};

countSeconds(3);

위 코드는 1, 2, 3을 1초 간격으로 출력하는 의도로 만든 예제이다. 하지만 결과는 4가 연속 3번 1초 간격으로 출력된다. 클로저를 잘 이해했다면 이유를 쉽게 이해할 수 있을 것이다.

 

setTimeout 함수의 인자로 들어가는 함수는 자유 변수 i를 참조한다. 하지만 이 함수가 실행되는 시점은 countSeconds() 함수의 실행이 종료된 이후이고, i 값은 이미 4가 된 상태이다. 그러므로 setTimeout()로 실행되는 함수는 모두 4를 출력하게 된다.

 

이제 원하는 결과를 얻기 위해 이 코드를 수정해보자. 이를 위해서는 루프 i값 복사본을 함수에 넘겨준다. 이를 위해 즉시 실행 함수를 사용했다.

 

function countSeconds(howMany) {
	for (var i = 1; i<=howMany; i++) {
    	(function (currentI) {
          setTimeout(function() {
              console.log(currentI);
          }, currentI * 1000);
       }(i));
    }
};

countSeconds(3);

즉시 실행 함수를 시켜 루프 i 값을 currentI에 복사해서 setTimeout()에 들어갈 함수에서 사용하면, 원하는 결과를 얻을 수 있다.

LIST