function 외부함수() {
	const 외부함수의변수 = 1;

	function 내부함수() {
		console.log(외부함수의변수);
	}

	setTimeout(내부함수, 0); // 1. callback
	return 내부함수; // 2. return
}
  1. 클로져는 내부함수가 외부함수 컨텍스트의 바깥으로 나왔을 때(return 혹은 비동기 함수 인자 전달을 통해), 외부함수의 변수/함수를 참조할 수 있는 현상이다.

  2. 참조가 가능한 이유는 내부함수의 실행컨텍스트 객체의 Lexical Environment의 outer 프로퍼티가 외부함수의 LexicalEnvironment를 참조하고 있기 때문이다.

  3. 외부함수가 종료된 이후에 내부함수가 실행될 때, 내부함수의 outer가 외부함수의 Lexical Environment에 대한 참조를 유지하고 있기 때문에 가비지컬렉팅 당하지 않는 것이다.

  4. 여기서 실행컨텍스트는 함수가 호출될 때 생성되는데, 내부함수의 outer는 함수가 호출될 때 이미 종료되어 있을 외부함수 실행컨텍스트의 참조값을 어떻게 갖고 있는걸까.

  5. 자바스크립트는 내부함수의 선언 시점에 외부함수의 Lexical Environment를 함수객체에 저장한다.

    Untitled

    1. 함수객체에는 [[Environment]]라는 internal slot이 있는데, 이것은 내부함수를 선언한 외부함수의 LexicalEnvironment를 담게된다.
    2. 이후 함수가 실행될 때 outer에는 [[Environment]]의 값이 사용되게 된다.
  6. 내부함수를 바깥으로 내보내지 않으면 함수가 종료됨에 따라 내부함수와 외부함수 모두 참조카운트가 0이 되어 순차적으로 가비지컬렉팅 되겠지만, 클로져 현상을 만들면, 바깥으로 내보내진 내부 함수 객체의 [[Environment]]가 이미 종료된 외부함수의 Lexical Environment를 참조하고 있으므로 종료된 이후에도 가비지 컬렉팅되지 않고 참조할 수 있는 것이다.

레퍼런스

https://262.ecma-international.org/6.0/#sec-ecmascript-function-objects