brunch

You can make anything
by writing

C.S.Lewis

by 강관우 Jul 09. 2016

자바스크립트 클로저

클로저, 어디까지 알아보셨어요?

 클로저, 정말 자주 들어본 말입니다.

특히 자바스크립트를 띄엄띄엄 보던 학부생 시절, 저와 같은 분들은 클로저를  두번( 사실 여러번... ) 검색해봤기 때문에 정의는 눈에 익으실 겁니다.


 클로저(closure)는 내부 함수가 외부 함수의 맥락(context)에 접근할 수 있는 것을 가리킨다.- 생활코딩


 사실 위 정의가 대박 명쾌하지만, 단어 하나하나 오롯이 이해하고 나야 문장 전체를 이해할 수 있는 것 같습니다.

 

 이 포스트는 " 클로저(closure)는 내부 함수가 외부 함수의 맥락(context)에 접근할 수 있는 것을 가리킨다."라는 문장을 이해하기 위해서 '맥락(context)'에 집중하는 포스팅입니다.


 제 머릿속에서 클로저를 이해하기 위해서 선행되어야 '했을' 흐름은 다음과 같습니다.

실행 컨텍스트 개념

활성 객체( 혹은 변수 객체 )

스코프 체인

그리고 대망의 클로저


먼저 컨텍스트란 무엇일까요?

C와 같은 언어에서 Call Stack이란 것을 들어 본 적 있을 것입니다. 콜 스택은 함수를 호출할 때 해당 함수의 호출 정보가 차곡차곡 쌓여있는 스택을 의미합니다. 자바스크립트에서도 이와 같이 함수가 실행될 때

실행에 필요한 정보들이 저장되는 스택(컨텍스트)이 생성되고, 쌓입니다.


하지만 자바스크립트에서 스택이란 개념을 글로벌 환경으로 가지고 있는 것이 아니라, 각 컨텍스트마다 리스트 형식으로 자신이 실행되었던 환경에 대한 정보들을 모두 저장하고 있습니다.

 다시 말하자면, 실행 컨텍스트는 특정 경우마다 생성되어 서로 연관되어 있는 메모리 영역이라고 할 수 있습니다.


 간단히 실행 컨텍스트를 정의한다면 실행 가능한 자바스크립트 코드 블록이 실행되는 환경입니다.

 

이러한 실행 컨텍스트가 생성되는 경우는 크게 세 가지 경우입니다.

- 전역 실행 컨텍스트

- eval() 함수로 실행되는 코드

- 함수 안의 코드를 실행할 경우


 우리는 이 세가지 경우 중에서 함수를 실행하여 실행 컨텍스트가 생성되는 경우를 보면서 컨텍스트의 구조를 이해해보겠습니다.

function execute(param1, param2){
    var a = 1, b = 2;
    function func(){
         return a+b;
    }
    return param1 + param2 + func();
}

execute(3, 4);


 위에서 execute(3, 4); 줄이 실행될 때 실행 컨텍스트가 생성되고, 활성 객체가 만들어집니다.

 실행 컨텍스트가 생성되면 자바스크립트 엔진은 해당 컨텍스트에서 실행에 필요한 여러 가지 정보를 담을 자바스크립트 객체를 생성하는데, 이를 활성 객체라고 합니다.

"실행 컨텍스트 안에는 활성 객체가 있다."

활성 객체는 arguments 객체 생성, 스코프 정보 생성, 변수 생성, this 바인딩, 코드 실행(표현식) 순으로 객체 프로퍼티들이 생성됩니다.

위 그림이 실행 컨텍스트와 활성 객체의 구조도입니다. 바로 이 컨텍스트 영역이 execute 함수가 참조할 수 있는 값들에 대한 유효 범위, 즉 바로 스코프가 됩니다.


 여기서 눈여겨볼 부분이 바로 [[Scope]] 프로퍼티입니다. 이 프로퍼티는 리스트로 되어 있습니다.

이 리스트 변수 안에는 지금 실행되는 컨텍스트의 참조 값이 저장되고, 추가적으로 execute를 실행시킨 함수가 가진 Scope 프로퍼티들을 복사합니다. 다시 말하자면, 상위 실행 컨텍스트에 대한 정보도 가지고 있다는 말이 됩니다.

 

 외부 함수의 프로퍼티에 접근할 수 있는 이유는 바로! 이 리스트를 통해서 체이닝되어 있기 때문입니다.

 

 이 메커니즘을 스코프 체이닝이라고 합니다.

 스포크 체이닝에 대한 내용을 다시 한번 간단 정리한다면,

 - 각 함수 객체는 [[scope]] 프로퍼티로 현재 '실행 중인' 컨텍스트의 스코프 체인을 참조한다.
 - 현재 실행되는 함수 객체의 [[scope]] 프로퍼티를 복사하고, 새롭게 생성된 변수 객체를 해당 체인의 제일 앞에 추가한다.
 - 즉 스코프 체인 = 현재 실행되는 컨텍스트의 변수 객체 + 상위 컨텍스트의 스코프 체인이다.


그럼 이쯤에서 다시 한번 클로저에 대한 정의를 구경해볼까요?

" 이미 생명 주기가 끝난 외부 함수의 변수를 참조하는 함수를 클로저라고 한다."


 "클로저(함수)는 클로저(함수) 스코프 안에서 클로저(함수)를 만든 외부 스코프에 "항상" 접근할 수 있다."


 자바스크립트에서 함수는 실행 컨텍스트를 가지고 이 실행 컨텍스트(스코프)는 외부 함수에 대한 실행 컨텍스트에 대한 참조값도 가지고 있으므로, 외부 함수가 종료되어 스코프에 접근하지 못할 것 같은 상황에서도 내부 함수는 외부 함수 프로퍼티에 접근할 수 있다는 개념입니다.


Closure라는 단어 자체의 의미를 생각해본다면, 자유 변수에 대해서 닫혀있다가 아니라, 가까워져 있다, 엮여있다는 의미라는 것을 이해하시겠나요?


함수가 생성될 때 환경을 그대로 유지해서 실행할 시점에 활용해야 할 때 클로저는 유용하게 사용될 수 있습니다.



 

 스코프의 활용과 주의사항에 대한 내용은 다른 아티클들로 대신하겠습니다!


http://bonsaiden.github.io/JavaScript-Garden/ko/#function.closures



 https://opentutorials.org/course/743/6544


 

브런치는 최신 브라우저에 최적화 되어있습니다. IE chrome safari