본문 바로가기

JavaScript/AboutJS

[JavaScript] Closure (클로져)

 

클로저(Closure)는 

1. 내부 함수와

2. 그 함수가 선언될 때의 렉시컬 환경(Lexical Environment)의 조합 이다.

 

1. 내부 함수: 다른 함수 내부에 정의된 함수
2. 렉시컬 환경: 함수가 선언될 때 생성되는 환경으로, 해당 함수의 스코프에 있는 모든 변수와 함수를 포함.

 

 클로저의 동작: 내부 함수가 외부 함수의 변수에 접근할 수 있고, 외부 함수가 반환된 후에도 이 접근이 유지된다.

 

실행 컨택스트에서 봤던 Outer Environment Reference 에서 상위 스코프의 요소들에 대한 정보를 알고 있다.

 

어떤 특별한 개념이 아닌 함수의 생성과 함께 자연스럽게 발생하는 게 클로저라는 현상이지만, 

우리가 특별히 언급할 때는 주로 상위 스코프에서 선언한 변수를( 렉시컬 환경 ), 내부 함수에서 참조할 경우에

일어나는 특정한 사용 사례나 동작을 가리킨다.

var outer = function () {
  var a = 1
  var inner = function ( ) {
   return ++a
  }
  return inner
}
var outer2 = outer() 
console.log(outer2()) // 출력 : 2
console.log(outer2()) // 출력 : 3

 

 

var outer2 = outer()  이 코드로 outer 함수 종료 후,

outer2 변수에 inner 함수는 리턴되게 되는데, 이 inner 함수 내부에는

상위 스코프의 outer 함수의 지역변수 a가 계속 참조 중인 상태이기 때문에

outer 의 실행 컨텍스트는 종료가 됬지만, 내부의 변수는 죽지 않고 살아 있는 상태가 되버렸다.

 

그리고 console.log(outer2( )) 로 outer2 를 호출하게 되면 inner 실행 컨텍스트가 생성되고,

본인의 내부에는 a 가 없으니 상위 스코프 outer 의 변수를 2로 바꾸게 된다.

 

그리고 console.log(outer2( )) 가 완전히 종료되면 inner 의 실행 컨텍스트는 사라지지만 a는 계속 참조중이므로

위와 같은 그림이 된다. outer 의 지역변수 a는 계속 살아남아있게 되는데,

전역 컨텍스트가 종료되면(프로그램이 종료되면) 자동으로 a도 사라지게 된다.

강제로 메모리 관리를 위해 현재의 closure( a변수)  를 GC( Garbage Collection ) 대상으로 주려면 

outer 2 = null 을 해주어 inner 와의 연결 고리를 끊어주면 된다.

 

a변수가 사라지지 않으면서 남아 있는 이 현상이 클로저의 특별한 현상이다.

 

이 말은 함수 종료 후에도 지역변수를 사라지지 않게 컨트롤 할 수 있다는 것이다.

이게 클로저로 얻는 가장 큰 이점이며

 

1.  데이터 캡슐화
2.  함수 팩토리 생성
3.  콜백 함수에서 외부 변수 접근

 

등을 할 수 있는 것이다.

 

 

1.  데이터 캡슐화의 예시

 

클로저를 이용해 private 변수를 모방할 수 있다.

   function createPerson(name) {
     let age = 0;
     return {
       getName: () => name,
       getAge: () => age,
       setAge: (newAge) => { age = newAge; }
     };
   }

   const person = createPerson("Alice");
   console.log(person.getName()); // "Alice"
   person.setAge(30);
   console.log(person.getAge()); // 30

person.age를 직접 접근할 수 있는 게 아닌 getter, setter 를 통해서만 접근할 수 있다

 

 

2. 함수 팩토리를 만들 때 ( 팩토리 패턴 )

 

클로저를 이용해 특정 기능을 가진 함수를 생성할 수 있다.

   function multiply(x) {
     return function(y) {
       return x * y;
     };
   }

   const double = multiply(2);
   console.log(double(5)); // 10

 

 

3. 콜백 함수에서 외부 변수 접근

콜백에서 외부 변수를 올바르게 참조할 수 있게 해준다.

   for (var i = 0; i < 5; i++) {
     setTimeout(function() {
       console.log(i);
     }, 1000);
   }
   // 예상과 달리 5가 5번 출력됨

   // 클로저를 이용한 수정
   for (var i = 0; i < 5; i++) {
     (function(j) {
       setTimeout(function() {
         console.log(j);
       }, 1000);
     })(i);
   }
   // 0, 1, 2, 3, 4가 출력됨

 

 

본 내용은 정재남님의 코어 자바스크립트 강의를 바탕으로 만들어졌습니다.