웹개발 및 최신 테크 소식을 전하는 블로그, 웹이즈프리

HOME > js

자바스크립트 클로저를 알아보고 다양한 예제 알아보자

Last Modified : 2019-02-26 / Created : 2017-05-31
4,332
View Count
자바스크립트의 클로저(Closure)에 대하여 자세히 정리한 내용이 없는 것 같아 이번 포스팅을 기회로 클로저에 대한 설명과 예제를 모두 담아보려합니다.



# 클로저(Closure)란?
클로저에 대하여 가장 기본적인 정의는 다음과 같습니다.

"클로저는 내부함수로 외부함수의 스코프에 존재하는 변수와 파라미터에 접근 가능한 것을 말한다."
"클로저는 외부환경의 조건을 가지는 내부함수를 말한다."



풀이하면 외부 스코프 영역에 접근 가능한 내부함수를 일컬어 클로저(Closure)라고 합니다. 클로저에 대한 정의는 조금씩 다르나 그 의미는 결국 같습니다. 그럼 클로저를 사용하면 무엇을 할 수 있을까요?



# 클로저의 특징 및 예제보기
아래는 클로저가 가지는 고유의 특징들과 이를 알아보는 예제소스입니다.

I. 외부 함수의 Return 된 이후에도 계속해서 내부 함수는 외부 변수와 파라미터에 접근할 수 있다.
아래는 클로저를 사용하는 간단한 예제입니다. 코드를 동작시키면 현재 사이트의 url을 반환합니다.
function getUrl(url) {
  var httpStr = 'http://';
  return function () {
    return httpStr + url;
  }
};

위 코드를 webisfree라는 변수에 담아 함수 geUrl()을 실행하면 아래와 같이 결과가 나타납니다.
webisfree = getUrl('webisfree.com');
webisfree();

'http://webisfree.com

위 예제는 클로저를 사용하여 getUrl()함수가 이미 return 되었으나 그 내부의 익명함수는 계속해서 httpStr 내부 함수와 url 파라미터에 접근할 수 있습니다.


II. 외부 함수의 값이 아닌 참조를 저장한다.
클로저의 내부 함수가 접근하는 외부 함수의 변수는 실제값을 가지는 것이 아니라 참조하여 메모리에 저장합니다. 외부 함수의 변수를 참조하여 저장하기 때문에 클로저에서 이 값은 항상 마지막에 저장된 값만 가지게 됩니다. 이는 의도하지 않은 결과를 가져오기도 하는데 아래의 for 반복문에서 어떤 문제가 나타나는지 알아보겠습니다.
for (var i = 0; i < 10; i++) {
  setTimeout(function() {
    console.log(i);
  }, i * 100);
}

위 예제를 생각해보면 0.1초마다 0부터 9까지의 값을 출력할 것이라 예상할 수 있습니다. 결과는 마지막 값인 9가 10번 출력되게 됩니다. 그 이유는 물론 내부의 익명함수에 클로저가 생성되었기 때문입니다.

이런 문제점을 해결하기 위한 방법으로 어떤 방법이 있을까요? 그럼 위 코드를 아래와 같이 수정해보도록 하겠습니다.


! 즉시실행호출함수방식(IIFE)을 사용한 방법
이번 예제에 IIFE(Immediately Invoked Function Expression)를 사용한 이유는 일반적으로 클로저 참조값에 대한 이슈를 해결하기 위하여 이 방법을 많이 사용되기 때문입니다. 아래의 코드를 실행하면 어떻게 될까요?
for (var i = 0; i < 10; i++) {
  setTimeout((function() {
    console.log(i);
  })(), i * 100);
}

이 경우 위 결과와는 다르게 0-9까지의 숫자가 출력됩니다. 다만 즉시호출되므로 의도한 setTimeout()의 시간지연이 이루어지지 않게되는 문제가 있습니다. 아래 방법은 해당하는 i의 값을 인자로 가지는 각각의 함수를 호출하고 그 안에서 시간지연이 나타나는 방법입니다.
for (var i = 0; i < 10; i++) {
  showLog(i);

  function showLog(i) {
    setTimeout(function() {
      console.log(i);
    }, i* 100);
  }
}

위 예제는 참고로 알아두시면 될 것 같습니다.

! let을 사용하는 방법, EC6 / ES2015
ECMAScript 6부터는 let을 사용하여 변수를 선언, 이를통해 블록 스코프를 가지는 변수를 만들 수 있습니다. let을 사용하면 참조값이 저장되는 것을 피할 수 있습니다.



! 클로저에 

따른 메모리 누수 제거하기
이처럼 변수를 참조하는 클로저는 해당 변수값을 계속해서 유지하는 과정에서 메모리 누수(Memory Leaking)가 발생할 수도 있습니다. 가비지컬렉터를 사용해 메모리를 회수하기 위하여 해당 함수를 종료, 파괴하는 과정이 필요합니다. 이를 위해 아래와 같이 null을 선언할 수 있습니다.
getUrl = null;

간단한 습관이지만 매우 중요합니다.




# 클로저 활용하기


클로저는 특정한 환경을 가지는 개별 함수 영역을 만들 수 있으며 이를 비동기 방식, 이벤트 동작 후 발생하는 콜백에 적용이 가능합니다. 많이 사용되는 jQuery 역시 클로저를 사용하여 구현되고 있습니다.

또한 타이머에 의하여 비동기로 실행되는 콜백함수에도 많이 사용됩니다.

Previous

angularjs one way, two way 바인딩 알아보기

Previous

자바스크립트 숫자의 자리수를 구하는 방법은?