본문 바로가기
JAVASCRIPT

Closure의 이해

by escaper101 2020. 11. 17.

우선 closure는 우리 개발자가 직접 생성하는 것이 아닌 특정 상황에서 JavaScript에 의해 자동으로 나타나는 결과이다. 우리가 closure를 직접 만들진 않지만 어떤 상황에서 어떤 원리에 의해 closure가 생성되는지 알아야 적절한 때에 용도에 맞게 closure를 활용할 수 있을 것이다. 

 

몇가지 예제 코드와 해당 코드가 실행될 때의 JavaScript 엔진의 동작 방식을 통해 closure를 이해하보자.

const attack = function() {
  let hp = 100;

  return function() {
    hp--;
    console.log(`Your current HP: ${hp}`)
  };
};

const user = attack();

 

 

콜 스택과 스코프

 

코드와 첨부된 사진을 같이 보면 global 실행 컨택스트(EC)에는 attack 함수와 user 변수가 선언되어 있다. 따라서 attack 함수와 user변수가 global 스코프에 포함된다. 자바 스크립트가 10번 줄을 읽으면 마침내 attack() 함수에 대한 EC가 생성되어 call stack에 들어간다. attack() 함수는 hp 변수를 가지고 있다. 따라서 attack() 함수 스코프에 hp 변수가 생성된다. 또한 attack() 함수는 스코프 체인에 의해 그 부모 스코프에 접근 가능한 것을 알 수 있다. 

 

attack() 함수는 코드를 보면 알 수 있듯이 4번 줄에서 함수를 리턴한다. 리턴된 함수는 user 변수에 담긴다. 이제 attack() 함수의 실행이 끝났으니 이 함수의 EC은 콜 스택에서 사라진다. 이와 동시에 attack() 스코프도 사라진다.

 

 

attack() 함수의 실행이 끝난 후

const attack = function() {
  let hp = 100;

  return function() {
    hp--;
    console.log(`Your current HP: ${hp}`)
  };
};

const user = attack();

user(); // Your current HP: 99

attack() 함수 실행 완료와 동시에 콜 스택에서 사라진 attack() 함수의 실행 컨택스트와 스코프는 회색으로 표현했다. 

user() 함수 실행

위에서 attack() 함수의 실행이 끝나고 attack() 함수가 리턴한 함수를 user 변수에 담는 작업까지 마쳤다. 그리고 user() 함수를 부르자 그 결과는 12번 줄의 주석 내용과 같다. 뭔가 이상하다. 분명 attack() 함수는 실행이 끝나 콜 스택에서 사라졌는데 user() 함수에서 attack() 함수의 스코프에 있는 hp 변수에 접근이 가능하다. 어떻게 된 것일까? 바로 closure 덕분이다. 

Closure는 어떤 함수로 하여금 그 함수가 생성된 시점의 실행 컨택스트에 접근 가능하게 한다. 즉, 우리의 예시로 돌아가면 user() 함수는 attack() 함수의 실행 컨택스트 안에서 생성되었다. 따라서 user() 함수는 언제나 그 함수가 생성된 시점의 실행 컨택스트 (attack() 함수의 실행 컨택스트)에 접근 가능한 것이다. attack() 함수의 실행 컨택스트는 attack() 함수의 실행이 완료된 시점에서 콜 스택에서 사라졌지만 user() 함수에 계속 남아있다. 

 

긴 포스팅이었지만 간단히 요약하면 다음과 같다. 

1. 함수는 그 함수가 생성된 시점의 실행 컨택스트에 언제나 접근할 수 있다.

- 심지어 그 실행 컨택스트가 더이상 존재하지 않더라도 접근 가능하다.

2. Closure는 그 함수에 남아있는 실행 컨택스트의 변수들을 말한다. 

 

이 포스팅이 closure의 동작 원리를 파악하는데 도움이 되었으면 한다. 

'JAVASCRIPT' 카테고리의 다른 글

Runtime 과 Call Stack  (0) 2020.11.28
생성자 함수와 Prototype  (0) 2020.11.17
this 키워드  (0) 2020.11.16
Hoisting과 Temporal Dead Zone (TDZ)  (0) 2020.11.16
Scope와 Call Stack  (0) 2020.11.14