해당 코드를 콘솔창에 쳐보면 bar함수는 closer임을 확인할 수 있다.
코드는 평갸/실행이 완료되면 콜스택에서 pop되면서 가비지 컬렉터가 해당 코드의 실행컨텍스트와 렉시컬환경을 쓱싹쓱싹 쓸어간다.
하지만 만약 중첩함수가 상위 스코프의 식별자를 참조하고 있고, 중첩함수가 외부함수보다 더 오래유지되는 경우에,
코드가 평가완료되어 콜스택에서 pop될 때 (실행컨텍스트는 삭제되고) "렉시컬환경은 살아남는다".
그것이 바로 "클로저"이다.
클로저는 단순히 중첩함수가 아니다. 클로저는 상위 스코프의 식별자(위의 코드의 경우 foo함수의 x)를 참조(console.log로 참조하고 있다)하고,
참조하고있는 중첩함수가 외부함수보다 좀 더 오래 살아남는 중첩함수에만 한정되는 개념이다.
--- 주관 주의 ---
위의 코드는 자바스크립트엔진이 런타임이전에 함수선언문 function foo를 등록하고(내부코드는 런타임때)
변수선언문인 const bar을 등록한다. 그다음 런타임때 const bar에 foo()를 등록하고 bar() 함수를 실행한다.
함수 bar에는 foo()가 등록되어있기에 function foo 함수 내부코드를 평가 및 실행하기 시작한다.
그러면 함수 foo의 지역 변수로 x와 y가 각각 1,2로 바인딩된다.
그러다가 function bar을 만나고, foo함수는 잠시 중단된다음 bar함수의 내부코드가 평가/실행된다.
이때 우리는 console.log(x)로 x를 출력하는데, bar함수에서는 변수 x가 없으므로 상위스코프인 foo로 올라가서 너네쪽엔 x가 있냐고 물어본다.
foo에서는 x가 있으니 x의 값인 1을 출력해준다. 이것이 바로 "상위스코프의 식별자 참조"이다.
이제 bar함수가 종료되고 foo로 돌아간다. foo에서는 함수 bar을 반환하면서 foo함수도 종료된다.
(395p) 이 때 foo함수의 실행컨텍스트는 스택에서 제거되지만 렉시컬 환경까지 소멸하지 않는다. 왜냐하면 foo함수의 렉시컬환경은
bar 함수의 [[Environment]] 내부슬롯에 의해 참조되고(상위스코프로 등록),
"bar함수는 전역변수 const bar에 의해 참조되고 있기(중첩함수가 외부함수보다 더 오래 유지될 수 있는 이유)" 때문이다.
* (궁금) "bar함수는 전역변수 const bar에 의해 참조되는게 중첩함수가 외부함수보다 더 오래 유지될 수 있는 이유인 이유는?"
: 솔직히 말하자면 난 왜 이렇게 설명하는 이유를 모르겠음... "실행컨텍스트는 외부함수가 종료되면 전역으로 다시 돌아가는데(물론 바로 pop됨), foo함수를 전역변수로 바인딩하기 때문에 외부함수보다 좀 더 오래 살아남는다고" 추상적으로 표현한거라고 이해했는데 흠
굿 ㅇㅅㅇ