[JavaScript] Closure

2022. 4. 2.공부/JavaScript

728x90

프로그래밍에서 사용되는 '변수'는 scope 안에서만 유효하다. Java에서는 { } 안을 scope라고 정의하며 중괄호 내부에서만 정의된 변수를 참조 가능하지만, JavaScript에서 var 자료형으로 변수를 선언한다면 블록 밖에서도 var를 전역 변수처럼 사용할 수 있다. 그래서 JavaScript에서는 '함수 내부'를 scope라 지칭한다.

 

ES6에서 let과 const 키워드가 추가되어 함수가 아닌 for,if같은 코드 블럭 안에서 지역 변수를 선언할 수 있지만, JS 특유의 "Closure"라는 개념은 기본적으로 함수를 일급 객체로 취급하는 함수형 프로그래밍 언어의 특성이다. 함수형 프로그래밍 언어에서 상위 스코프의 식별자를 참조하는 함수를 Closure라고 부르고, 이 Closure가 참조하고 있는 상위 스코프보다 오래 살아남아 있다면, 상위 스코프가 호출되었다가 사라지더라도 클로저가 참조하고 있는 사라진 함수의 식별자에 접근할 수 있다. 

 

let one;
one = 1;
fucntion addOne(num){
	console.log(one+num); // Closure
    }
addOne(5);

 

JS 함수를 호출하면 함수 코드가 평가되어 생성 순으로 콜스택에 함수 실행 컨텍스트가 쌓인다. 이때 가장 나중에 쌓인 컨텍스트부터 실행되고 실행 후 스택에서 pop되어 제거된다.  addOne은 클로저로 one을 참조하고 있기 때문에 one이 호출 후 소멸된 이후에도 addOne에서 사라진 변수 one의 값을 기억하여 들고 있게 된다. 

 

http://latentflip.com/loupe/ 이용

 

 

let b = 1; // 전역 변수이기 때문에 호출한 후 계속 존재하지만,
        
function outer() {
let b = "비입니다"; // 지역 변수이기 때문에 호출했다가 사라진다.
let inner = function() 
{ console.log(b); } // 내부 함수 inner는 Closure이기 때문에 생성 시점의 외부 지역 변수 b를 들고 있게 됨
return inner; // "비입니다" 출력
}

outer(); // inner가 들고 있는 outer 내의 외부 지역 변수 b가 호출됨

 

위의 코드에서 outer 내의 inner는 Closure이며, outer 함수의 호출로 inner를 리턴하게 되면, 전역 변수 b가 아닌 생성 시점의 외부 지역 변수 b가 호출된다. 이를 통해 전역 변수 b의 값은 1로 바뀌지 않고 은닉된다. 이렇게 클로저는 상태를 안전하게 변경하고 유지하기 위해 사용되는 것이다. 상태를 안전하게 은닉하고(전역 변수 b) 특정 함수에게만 상태 변경을 허용한다(Closure 함수만이 지역 변수 b에 접근하여 변경 가능)

 

  function makeCount() {
      let num = 0; // 지역 변수이기 때문에 한번 실행 후 사라짐
      return function() {
          return num++; // Closure, let num 참조하여 들고 있음
     }
 }
        let count = makeCount();
        console.log(count()); // 0
        console.log(count()); // 1
        console.log(count()); // 2

 

위의 코드에서 makeCount 내의 함수는 Closure이며, 생성 시점의 외부 지역의 변수 0을 들고있게 된다. makeCount함수를 변수 count에 저장하여 첫번째 실행 시 0 + 0 = 0이 리턴되고, 두번째 실행 시 0 + 1 = 1이 리턴, 세번째 실행 시 1 + 1 = 2가 리턴된다. 이로써 지역 변수 num의 값은 0으로 은닉되자만 특정 함수에게만 상태 변경을 허용하는 방법으로 num에 접근이 가능하다.