본문 바로가기

프로그래밍/JavaScript(JS)

자바스크립트(JavaScript) - 클로저(Closure)

자바스크립트에는 클로저라는 기능이 존재합니다.

클로저는 Execution Context를 알아야 이해가 되니 참고하시기 바랍니다.

https://bearcomputer.tistory.com/28

클로저는 무엇인가?

아래에 코드를 먼저 확인해보겠습니다.

function ab()
{
    var count = 0;
    return function() {
    	return count++;
    }
}

var a = ab();
console.log(a()); // -> 0
console.log(a()); // -> 1
console.log(a()); // -> 2

리턴하는 함수가 ab 함수에 있는 count변수를 사용하고 있습니다. 이것이 클로저라는 구조를 가지고 있기 때문에 가능한 일입니다.

클로저는 함수내부에 선언된 내부 함수가 외부 함수의 Execution Context에 있는LexicalEnvironment를 참조하는 구조라고 볼 수 있습니다.

위 코드의 작업을 간단히 알아보도록 하겠습니다.

  1. ab() 함수가 호출이 되면 새로운 Execution Context가 만들어지고 ab() 함수 내부에 있는 지역 변수들과 내부 익명 함수가 Lexical Envrionment에 바인딩 됩니다. 익명 함수가 생성 될때 현재 ab()함수의 LexicalEnvrionment를 정보를 저장해둡니다.
  2. 변수 값 초기화
  3. 익명 함수 리턴
  4. a() 함수 호출
  5. a() 함수가 호출이 되면 새로운 Execution Context가 만들어지고 익명 함수에 저장했던 ab() 함수의 LexicalEnvrionment를 외부 렉시컬 환경 참조로 설정합니다.
  6. count 변수를 찾아 외부 렉시컬 환경을 참조하여 ab() 렉시컬 환경에서 count 변수를 찾아 리턴합니다.

이렇게 보면 ab함수는 모든작업이 끝났지만 ab의 함수의 렉시컬 환경은 소멸하지 않고 그대로 남아있습니다.

소멸 하지 않는 이유는 내부 익명 함수가 ab() 함수의 LexicalEnvrionment를 참조하고 있기 때문에 가비지 컬렉션이 메모리에서 해제하지 않는것입니다.

따라서 아까 말했듯이 함수의 내부 함수가 외부 함수의 지역 변수를 찾아 외부 함수의 LexcialEnvrionment를 참조하는구조가 클로저입니다.

클로저를 사용하는 이유는?

이 클로저 기능을 이용하면 외부에서는 함수에 있는 변수 접근이 불가능 하기때문에 캡슐화를 구현하여 데이터를 은닉할 수 있고 함수가 호출이 끝나도 내부 함수가 있기 때문에 계속 해서 메모리에서 지워지지 않고 유지가 되어 상태를 유지 할 수 있습니다. 또 한 함수를 객체처럼 새로 만들어 사용할 수도 있습니다.

 

캡슐화 예시


function ab()
{
    var a = 0;
    return {
      getA : function() { return a; },
      setA : function(n) { a = n; }
    };
}

var test = ab();
console.log(test.getA()); // -> 0
console.log(test.setA(2));
console.log(test.getA()); // -> 2
console.log(test.setA(10));
console.log(test.getA()); // -> 3

리턴을 꼭 함수로만 주지 않아도 객체로 주어도 가능합니다.

함수 새로 만들기 예시

function ab()
{
    var a = 0;
    return {
      getA : function() { return a; },
      setA : function(n) { a = n; }
    };
}

var test = ab();
var test2 = ab();
console.log(test.getA()); // -> 0
console.log(test2.getA()); // -> 0
console.log(test.setA(2));
console.log(test2.setA(4));
console.log(test.getA()); // -> 2
console.log(test2.getA()); // -> 4

각 코드처럼 상태를 최신화 되어 유지 할 수 있고 변수가 외부에 노출되지 않고 안전하게 데이터가 변경이 가능해집니다.

클로저의 단점?

클로저 기능을 사용하면 메모리에서 제거 되지 않기 때문에 클로저 기능을 막 사용하면 메모리 낭비가 발생하니 잘 생각하며 효율적으로 사용해야 하고 사용이 끝났을때에는 낭비를 방지하기 위해 null을 대입하여 메모리를 해제 해주어야 합니다.

 

참고

모던 자바스크립트 입문(이소 히로시 지음, 서재원 옮김)

https://developer.mozilla.org/ko/docs/Web/JavaScript/Closures