실행 컨텍스트와 클로저

실행 컨텍스트(Execution Context)

  • 실행 가능한 코드가 실행되는 환경이다.
  • 실행 가능한 코드 : 전역코드, Eval코드(안씀), 함수코드(호출)
  • 변수와 함수가 호출되기 위한 환경이 만들어진다.
  • 자바스크립트 엔진은 코드를 실행하기 위해 실행에 필요한 정보를 알고 있으며, 실행 컨텍스트를 물리적 객체의 형태로 관리한다.
  • 실행에 필요한 정보 : 변수(객체의 프로퍼티, 전역변수, 지역변수, 매개변수), 함수선언(함수명, 함수), 변수의 유효범위(전역이냐 지역이냐), this(가리키고 있는 객체)

실행 컨텍스트 스택(=콜 스택)

  • 실행 컨텍스트가 생성되서 쌓이는 영역
  • 전역 실행 컨텍스트, 함수 실행 컨텍스트가 생성되면 실행 컨텍스트 스택에 쌓인다.
  • 함수를 호출하면 해당 함수의 실행 컨텍스트가 생성되며, 함수가 끝나면 해당 함수의 실행 컨텍스트가 사라진다.

실행 컨텍스트 3가지 객체

  • Variable Object(VO), Scope Chain(SC), this value
  1. Variable Object
  • 변수(함수표현식 포함), 매개변수와 인수, 함수선언의 정보를 담는 객체로 유일하며 최상위에 위치한 객체이다.
  • 전역 컨텍스트의 VO는 전역객체(GO)를 가리키고, 함수 컨텍스트의 VO는 활성객체(AO)를 가리킨다.
  • 전역 객체(GO)는 전역에 선언된 전역 변수, 전역 함수를 프로퍼티로 소유한다.
  • 활성 객체(AO)는 매개변수와 인수들의 정보를 배열의 형태로 담고 있는 arguments객체가 추가된다.
  • 전역 객체(Global Object)는 1개 생성, 활성객체(Activation Object)는 여러개 생성이 가능하다.
  1. Scope Chain
  • 스코프 체인은 일종의 리스트로서 중첩된 함수의 레퍼런스를 저장하고 있다.
  • 마지막 리스트는 항상 전역 객체(GO)를 가리킨다.
  • 함수 실행 컨텍스트의 스코프 체인의 경우, 레퍼런스로 자기 자신의 AO와 GO를 가리킨다.
  • 스코프 체인(리스트)을 검색하면 함수가 중첩 상태일 때, 하위함수 내에서 상위함수의 유효 범위까지 참조할 수 있게 된다.
  1. this value
  • this의 값이 할당된다.
  • 함수 호출 패턴에 의해 결정된다.

전역 코드에의 진입

  1. 전역 객체 생성
  • 컨트롤이 실행 컨텍스트에 접근하기 이전에 유일한 전역 객체(Global Object)가 생성된다.
  • 전역 객체에는 빌트인 객체와 BOM, DOM이 설정되어 있다.
  1. 실행 컨텍스트 생성 후 스택
  • 전역 코드로 컨트롤이 진입하면 실행 컨텍스트가 생성된 후, 실행 컨텍스트 스택에 쌓인다.
  1. 스코프 체인(SC)의 생성과 초기화
  • 전역 객체의 레퍼런스를 포함하는 리스트가 된다.
  1. Variable Instantiation(변수 객체화) 실행
  • Variable Instantiation은 VO에 프로퍼티와 값을 추가하는 것이다.
  • 변수, 매개변수, 인수정보(arguments), 함수선언을 VO에 추가하여 객체화한다.
  • 함수부터 변수 순으로 저장된다.

4-1. “변수 객체화의 순서”

    1. Function일 경우 매개변수(parameter)가 VO의 프로퍼티로, 인수(arguments)가 값으로 설정된다.
    1. 함수선언(함수표현식 제외)을 대상으로 함수명이 VO(VO가 가리키고 있는 객체)프로퍼티로, 생성된 함수 객체가 값으로 설정된다.(함수 호이스팅)
    1. 변수 선언을 대상으로 변수명이 VO(VO가 가리키고 있는 객체)의 프로퍼티로, undefined가 값으로 설정된다.(변수 호이스팅)
  1. 함수의 선언 처리(함수가 있다면)
  • 변수 객체화의 순서 2번처럼 함수명이 프로퍼티로, 생성된 함숫 객체(몸체)가 값으로 설정된다.(전역 함수일 경우 GO에 설정)
  • 생성된 함수 객체는 [[Scope]] 프로퍼티를 가지게 된다.
  • (함수 호출 실행 이전)[[Scope]]는 현재 실행 컨텍스트의 스코프 체인이 참조하고 있는 객체를 값으로 설정하고, (함수 실행 후)스코프 체인이 가리키는 변수 객체에 이미 함수가 등록되어 있으므로 함수선언식 이전에 함수를 호출할 수 있다. (함수 호이스팅)
  1. 변수의 선언 처리(변수가 있을때)
  • 변수 객체화의 순서 3번처럼 변수명이 VO(VO가 가리키고 있는 객체)의 프로퍼티로, undefined가 값으로 설정된다.
  • var 키워드로 선언된 변수는 선언과 초기화 단계가 한번에 이루어진다.
  • 변수 선언문 이전에 접근해도 VO에 변수가 undefined로 초기화된 상태로 존재하기 때문에 에러가 나지 않는다.(변수 호이스팅)
  1. this value의 결정
  • this value가 결정되기 이전에 this는 전역 객체를 가리키고 있다가 함수 호출 패턴에 의해 this에 할당되는 값이 결정된다.

전역 코드의 실행

  1. 변수값 할당
  • 변수값을 할당할 때는 VO(VO가 가리키고 있는 객체, 전역의 경우 GO)를 선두(0)부터 검색하여 해당 변수의 프로퍼티를 발견하면 값을 할당 한다.
  1. 함수 실행
  • 함수가 실행되면 새로운 함수 실행 컨텍스트가 생성된다.
  • 해당 함수로 실행 컨텍스트의 컨트롤이 이동하면 전역 코드와 마찬가지로 1. 스코프 체인의 생성과 초기화, 2. Variable Instantiation 실행, 3. this value 결정이 순서대로 실행된다.

함수 코드에의 진입

  • 전역 코드에의 진입과 순서는 같지만 다른 룰이 적용된다.
  1. 스코프 체인의 생성과 초기화
  • Activation Object생성**
  • AO에 대한 레퍼런스를 스코프 체인의 선두에 설정한다.
  • Activation Object는 arguments 프로퍼티를 초기화한다.
  • 스코프 체인의 마지막 레퍼런스 객체는 전역 객체를 참조한다.
  1. Variable Instantiation 실행
  • 함수 객체와 변수를 VO에 바인딩한다.(선언, 초기화)
  • 변수의 프로퍼티는 변수명, 값은 undefined로 VO에 저장한다.
  • 함수의 프로퍼티는 함수명, 값은 Function Object로 VO에 저장한다.
  • Function Object의 [[scope]] 프로퍼티가 생성된다.
  • [[scope]] 프로퍼티는 AO와 전역을 참조하는 리스트의 값을 갖는다.
  1. this value 결정
  • this에 할당되는 값은 함수 호출 패턴에 의해 결정된다.

함수 코드의 실행(함수에 변수가 존재할때)

  1. 변수 값의 할당
  • 지역변수를 할당할 때(현재는 내부함수일 경우), 스코프 체인이 참조하고 있는 VO를 선두(0)부터 검색하여 변수명에 해당하는 프로퍼티가 발견되면 값을 할당한다. (해당 영역에도 없으면 스코프 체인 리스트를 참조하여 GO를 검색하도록 한다.)

내부 함수 코드의 실행

  • 내부 함수가 실행되기 시작하면 새로운 실행 컨텍스트가 생성된다.
  • 여기서도 1. 스코프 체인의 생성과 초기화, 2. Variable Instantiation 실행, 3. this value 결정이 순서대로 진행된다.

클로저(closure)

  • 내부함수가 참조하는 외부함수의 지역변수가 외부함수에 의해 내부함수가 반환된 이후에도 life-cycle이 유지되는 것을 의미한다.
  • 외부함수가 내부함수보다 더 오래 유지되는 경우에 내부함수가 외부함수의 지역변수에 접근할 수 있고 외부함수는 외부함수의 지역변수를 사용하는 내부함수가 소멸될 때까지 소멸되지 못하고 상태가 유지되며 내부함수에 의해 소멸하게 되는 특성을 말한다.
  • 클로저에 의해 참조되는 외부함수의 변수를 자유변수(Free variable)이라고 부른다.
  • (실행 컨텍스트 관점에서)내부함수가 유효한 경우에 외부함수가 종료 되면 함수의 실행 컨텍스트도 소멸하지만, 함수 실행 컨텍스트의 AO는 유효하기 때문에 내부함수가 스코프 체인을 통해 참조할 수 있다.

클로저의 활용

  • 성능적인 면과 자원적인 면에서 손해를 볼 수 있다.
  • (실행 컨텍스트에서) 클로저로 참조하는 변수는 프로그램 종료 시까지 계속 메모리에 할당되어 있기 때문에 성능 상 좋다고 할 수 없다.(최소화하며 오남용하지 않아야 한다.)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<button type="button" onclick="myFunction()">Count!</button>

<p id="demo">0</p>

<script>
var add = (function () {
var counter = 0;
return function () {
return ++counter;
};
}());

function myFunction() {
document.getElementById('demo').innerHTML = add();
}
</script>
  • 전역 변수의 사용 억제를 위한 방식
  • 즉시 실행함수는 한번만 실행되므로 counter가 다시 초기화되지 않는다.
  • 외부함수의 변수 counter는 참조하는 함수(내부함수)가 소멸될때까지 유지된다.
  • counter는 외부에서 접근할 수 없는 private 변수이다.