“A closure is the combination of a function and the lexical environment within which that function was declared.”
클로저는 함수와 그 함수가 선언됐을 때의 렉시컬 환경(Lexical environment)과의 조합이다.
정의
변수나 함수 등의 식별자를 정의할 때 사용되는 명세
중첩된 어휘적 환경에 기반해 동작
Environment Record와 outer속성 포함
관련 문법
함수 선언
블럭문
Try-Catch문의 Catch절
종류
전역 환경
모듈 환경
함수 환경
const str = "어디서 실행될까??"
console.log("str");
function hello() {
const greeting = "안녕하세요";
console.log(greeting)
}
hello()
이 코드가 실행되면 큐 스택에는 Global EC(Execution Context, 실행 컨텍스트), hello() EX 순으로 쌓이게 된다.
EC 안에는 몇 가지 상태 컴퍼넌트가 존재하는데,
대표적으로 아래 세 가지가 있다.
function
function은 현재 컨텍스트가 함수로 생성되었다면 그 함수 객체를 가르킨다.
(Global EC의 경우 이 값은 null이 된다)
Variable Environment(VE)
VE는 두가지 속성을 가진다
Lexical Environment(LE)
LE는 VE와 비슷하지만 조금 다르다
함수는 실행 컨텍스트를 생성할 수 있는 객체로, Environment 속성이 있다.
이 속성에는 '자신이 선언 될 때의 Environment Record가 들어있다.
즉, 위 예시에서 hello 함수의 Environment는 global EC의 LE와 같다.
처음 만들어 질 때의 어휘적 범위를 그대로 유지한 함수.
어휘적 범위(LE) 바깥에서 해당 범위에 접근할 수 있다.
스코프는 함수를 호출할 때가 아니라 함수를 어디에 선언하였는지에 따라 결정된다.
이를 렉시컬 스코핑(Lexical scoping)라 한다.
위 예제의 함수 innerFunc는 함수 outerFunc의 내부에서 선언되었기 때문에 함수 innerFunc의 상위 스코프는 함수 outerFunc이다.
함수 innerFunc가 전역에 선언되었다면 함수 innerFunc의 상위 스코프는 전역 스코프가 된다.
1 function hello() {
2 const greeting = '안녕하슈';
3
4 return function() {
5 console.log(greeting);
6 };
7 }
8
9 const say = hello();
10 say();
코드가 실행되면 Global EC의 LE에 hello, say가 저장된다.
line 9에서 hello가 실행되면 hello EC(실행 컨텍스트)가 생성되고
LE에 greeting이 저장된 후 익명함수를 return한다. 그리고 보통은 함수 종료와 함께 hello EC는 사라진다. (다만 이 경우에는 사라지지 않는다.)
return된 익명함수는 say에 할당되고
line 10에서 say가 실행되어 line 4~6에 선언된 함수, 그 내부의 console.log가 greeting이라는 변수를 찾는다.
이 때, Global EC에 say라는 식별자가 hello 안에 있는 greeting을 참조하고 있기 때문에, hello 함수는 종료되어도 메모리에서 hello가 사라지지 않고 있는 것이다
함수는 자기자신이 선언될 때의 LE를 Environment라는 속성에 저장하고, EC를 만들면서 그 값을 outer에 넣는다.
이 과정이 있기 때문에 자신이 선언되었을 때 속해있었던 실행 컨텍스트의 값을 참조할 수 있는 것이다 => closure!!
캡슐화
컨텍스트 공유 (함수가 종료되어도 지역변수 사용)
함수를 반환함으로써 재사용 가능