본문 바로가기

카테고리 없음

자바스크립트 Closure (+ 실행컨텍스트, 렉시컬 환경)

반응형

오늘은 자바스크립트의 클로져에 대해 얘기해볼까한다. 그런데 클로져를 이해하기 위해서는 클로져가 실행될 수 있는 환경에 대한 이해가 먼저 필요하다.

 

자바스크립트 엔진는 자바스크립트 코드를 처리할때 평가와 실행의 과정을 거친다.

 

1. 평가

실행컨텍스트를 생성하고, 선언문(변수, 함수)만 먼저 실행하여 해당 실행 컨텍스트의 렉시컬 환경 안 환경 레코드에 key로 등록한다. 이때 호이스팅이 발생한다고 볼 수 있다.

 

2. 실행

실제로 실행하는 코드의 정보(식별자에 바인딩 될 값)를 실행 컨텍스트 안의 스코프에서 검색한다.

 

 

위의 내용은 자바스크립트를 처음 접하는 사람이 보기에는 낯선 단어가 꽤 많다. 하나씩 알아보자.

실행 컨텍스트

실행 컨텍스트는 코드가 실행될 수 있는 환경을 제공한다. 따라서 이 환경 속에는 코드가 원만하게 실행될 수 있도록 선언된 변수, 함수, 스코프, this에 바인딩 된 값 등의 내용이 담겨있다. 특히 이 중에서도 식별자와 스코프는 렉시컬 환경에서 관리된다.

렉시컬 환경

식별자와 식별자에 바인딩 된 값, 상위 스코프에 대한 참조를 담고 있는 자료구조이다. 코드를 실행하는데 필요한 정보를 담고 있는 것이다. key-value 형태로 데이터를 관리한다. 렉시컬 환경 안에는 environmentRecord, outerEnvironmentRecordReference가 있다.

environmentRecord

스코프에 포함된 식별자, 그리고 식별자에 바인딩 된 값을 가진다.

outerEnvironmentRecordReference

상위 스코프에 대한 참조를 가진다. 정확히는 해당 실행 컨텍스트를 실행한(상위 스코프)의 렉시컬 환경을 가리킨다. 이 참조값들을 이용해서 스코프 체인을 구성한다. 따라서 스코프 체인은 하위에서 상위를 가리키는 단방향 링크드 리스트 일 수 밖에 없다.

 

 

 

지금까지 얘기한 내용을 그림으로 간단히 정리해보면 위와 같다. 이해를 돕기 위해 렉시컬 환경안에 직접 envrironmentRecord, outerEnvironemntRecordReference를 그렸지만 사실 전부 참조로 동작한다.

 

위에서 본 것처럼 코드 실행순서는 콜 스택에 실행 컨텍스트를 넣음으로써 관리하고, 코드 실행에 필요한 정보는 렉시컬 환경에서 관리한다. 실행 컨텍스트와 렉시컬 환경은 별도의 객체이고, 실행 컨텍스트가 렉시컬환경을 참조한다. 이러한 구조를 바탕으로 우리는 클로져에 대해 알아볼 수 있다! 😭

클로져

클로져는 본인이 선언됐을 때의 환경을 잘 기억해서 나중에 그 환경을 잘 써먹는 함수이다.

 

조금 더 상황을 덧붙여서 말해보자면, 어떤(외부) 함수 안에 내부 함수가 리턴되고 있다고 하자. 외부 함수가 실행되고나서 (콜 스택에 push 되었다가 삭제되고) 리턴된 내부 함수가 실행됐을 때 이 내부 함수는 외부 함수의 지역 변수에 접근할 수 있다. 이때 내부 함수가 클로져이다. 

 

어떻게 그럴 수 있을까? 외부함수의 실행 컨텍스는 이미 콜 스택에서 제거되었는데, 어떻게 내부 함수는 외부 함수의 지역 변수에 접근할까?

 

바로 렉시컬 환경 덕분이다. 

 

아까 위에서 적은 내용을 다시 생각해보자. 실행 컨텍스트는 함수의 호출 순서를, 렉시컬 환경은 함수를 실행하는데 필요한 정보(지역 변수 포함)를 담고 있다. 두 개는 별도의 객체이다. 그렇다면 실행 컨텍스트가 사라진다고 해서 렉시컬 환경이 사라질까? 그렇지 않다. 렉시컬 환경은, 본인을 참조하고 있는 객체가 단 하나라도 있는 이상 가비지 컬렉터의 대상이 아니다. 실행 컨텍스트가 사라진다고 같이 사라지는 대상이 아니다.

 

따라서 외부 함수의 실행 컨텍스트는 콜 스택에서 사라졌지만 렉시컬 환경은 살아있고 리턴된 내부 함수가 실행될 때 내부 함수의 렉시컬 환경은 외부 함수의 렉시컬 환경을 참조하고 있다. 그리고 이 외부 함수의 렉시컬 환경에는 지역 변수의 정보가 담겨있다. 그래서 내부 함수는 외부 함수 존재 여부와 상관없이 외부 함수의 지역 변수에 접근할 수 있다.

 

 

 

🤔 느낀점

클로져의 예시 코드는 쉽게 찾아볼 수 있어서 넣지 않았다. 클로져가 어떻게 생겼는지보다는 어떻게 클로져가 동작할 수 있는지에 초점을 맞춰서 글을 쓰고 싶었다. 우테코 초반에 클로져에 대해서 발표를 한 적이있는데 4개월이 지나고 다시 이렇게 글로 정리하니깐 다시 한번 생각 정리를 할 수 있었다.

반응형