[이론] 자바스크립트 스코프와 클로저 정리

강재영
5 min readMay 22, 2019

--

혼자서 정리하는 자바스크립트 이론

1. 식별자 결정: 유효 범위 체인

자바스크립트에선 함수를 기준으로 범위를 나눕니다. 함수 안에서 변수가 선언되었을 경우 함수 안에 있는 전체 코드가 그 변수를 사용할 수 있는 유효범위가 됩니다. 하지만 전역 변수지역 변수가 같은 변수를 사용하다면 충돌이 일어납니다. 전역 변수의 유효 범위프로그램의 전체이고 지역 변수의 유효 범위함수 전체입니다. 이와 같이 동일한 변수를 사용하는 (예를 들어 변수 x를 사용하는 경우) 상황에서 어느 곳에 어떠한 변수 x를 할당할지 결정하는 작업을 식별자 결정(Identifier Resolution)이라고 합니다. 기본적으로 자바스크립트에서 식별자 결정 기준은 “안쪽에서 선언된 변수를 우선적으로 사용한다.” 입니다.

클로저까지 한 번에 정리하기 위해서 여기서 또 다른 방식의 표현를 정리하겠습니다. 함수의 매개변수와 지역 변수를 속박 변수라고 하고 그 외 나머지들은 자유 변수라고 합니다. 위에 코드에서 함수 g를 기준으로 하면 변수 c는 속박 변수가 되고 변수 b와 a는 자유 변수가 됩니다. 함수는 속박 변수로만 구성되어 있으면 닫힌 함수, 자유 변수를 하나라도 가지고 있으면 열린 함수 라고 합니다.

변수 c는 지역 변수이면서 속박 변수이기 때문에 쉽게 결정할 수 있습니다. 하지만 변수 b는 다릅니다. 함수 g의 바깥에서 선언된 자유 변수입니다. 변수 b를 식별하기 위해서 먼저 함수 g 범위를 검색하고 못 찾을 경우, 함수 g를 호출한 함수 f의 범위를 탐색합니다. 변수 b는 함수 f에 선언된 변수이기 때문에 함수 f 범위 안에서 찾을 수 있습니다. 이때 변수 b의 식별자를 결정합니다. 변수 a는 함수 g와 함수 f 바깥에 선언된 자유 변수입니다. 변수 b와 같은 방식으로 거슬로 올라가는 방식을 통해서 탐색합니다. 변수 a는 변수 b보다 한 단계를 더 거슬러 올라가 전역 범위에서 찾을 수 있습니다. 이때 변수 a를 찾아 식별자 결정 작업을 합니다.

함수의 유효 범위를 거슬러 올라가 식별자를 검색하고 찾아내는 과정을 걸친다.

식별자를 결정하는 방식은 이처럼 현재의 유효범위를 거슬러 올라갑니다. 변수가 속한 유효범위의 참조를 따라 찾아가는 방식입니다. 이러한 방식을 유효 범위 체인 이라고 합니다. (논리적인 연결고리, 스코프 체인, 외부 렉시컬 환경 체인 등 다양한 이름으로 부립니다.)

2. 가비지 컬렉션(garbage collection)

객체를 만들면 메모리 공간이 할당됩니다. 객체가 참조하지 않는 상태가 되었을 때 메모리 공간을 자동으로 없애주는 역할을 하는 것이 가비지 컬렉터입니다.

세 번째 줄에서 ‘p = null; ’을 실행하게 되면 변수 p는 더 이상 x,y를 참조하지 않게 되고 x와y를 참조하는 변수는 없게 됩니다. 이때 x와 y는 가비지 컬렉터에 의해서 메모리에서 해제됩니다.

참조되지 않는 객체는 가비지 컬렉터에 의해서 메모리 해제된다.

가비지 컬렉터는 브라우저마다 다르게 실행됩니다. 예를 들어 IE 6 이전 버전에서는 참조 카운터 방식을 사용하는데 이 방식은 고립된 순환 참조가 발생했을 때 메모리 누수를 해결하지 못한다는 단점이 있습니다.

순환 참조하는 객체는 가비지 컬렉터가 메모리를 해제할 수 없다.

3. 클로저(closure)

위에 코드를 스코프 개념과 가비지 컬렉션 개념을 더해서 다시 보겠습니다. 함수 g는 함수 f를 참조하고 있으며 함수 f는 전역 환경을 참조하고 있습니다. 따라서 함수 g는 자신의 유효범위 안에는 변수 c 뿐만 아니라 변수 b와 변수 a에 접근할 수 있습니다.

클로저 = 함수 객체 + 유효 범위 컴포넌트

클로저란 참조를 통해서 접근할 수 있는 유효 범위 체인에 있는 컴포넌트함수의 개체를 뜻합니다.

함수 g의 함수 객체가 함수 f를 참조하고 함수 f가 전역 지역를 참조하기 때문에 변수 b와 변수 a는 가비지 컬렉션 대상이 되지 않습니다. 따라서 함수 g의 참조를 받는 한 클로저는 메모리에서 해제되지 않습니다.

  • 클로저의 어원- 열려 있던 것을 닫는다

함수 g는 원래는 열린 함수이지만(자유 변수 a,b가 있음으로), 유효 범위 체인으로 변수 b와 a가 들여와서 실제로는 닫힌 함수처럼 됩니다.

4. 클로저의 성질

위 코드는 counter()가 호출될 때마다 함수 makeCounter가 지역 변수인 count 출력하고 그 다음에 count를 1 증가시키는 코드입니다.

함수 f는 변수 count를 참조함으로 함수 f는 함수 makeCounter를 참조합니다. 또한 변수 counter는 함수 f를 간접적으로 참조하게 됩니다. 이러한 구조 덕분에 변수 count는 가비지 컬렉션의 대상이 되지 않습니다.

makeCounter 함수의 지역변수인 count는 클로저의 내부에 저장된다. 그러므로 메모리 해제되지 않는다.

--

--