[JavaScript] 실행 컨텍스트

빵호·2021년 10월 17일
0

JavaScript

목록 보기
15/28
post-thumbnail

실행 컨텍스트

실행 컨텍스트(Execution Context)는 실행할 코드에 제공할 환경 정보들을 모아놓은 객체이다.

스택(Stack)과 큐(Queue)

스택(Stack)

스택은 프링글스를 생각하면 된다. 데이터를 맨 아래부터 a, b, c, d 순서대로 저장하지만 꺼낼 때는 반대로 맨 위부터 d, c, b, a 순서로 꺼내야 한다.

큐(Queue)

큐는 컨베이어 벨트를 생각하면 된다. 한쪽은 입력, 다른 한쪽은 출력만 담당하고 데이터를 a, b, c, d 순서로 저장하고 꺼낼 때도 a, b, c, d 순서로 꺼낸다. 하지만 종류에 따라 양쪽 모두 입력과 출력이 가능한 큐도 있다.

실행 컨텍스트와 콜 스택(Call Stack)

실행 컨텍스트

동일한 환경에 있는 코드들을 실행할 때 실행 컨텍스트를 구성하고, 이를 콜 스택에 쌓아올렸다가, 가장 위의 컨텍스트와 관련 있는 코드들을 실행하는 식으로 환경과 순서를 보장한다. '동일한 환경' 이란 하나의 실행 컨텍스트를 구성할 수 있는 방법으로 전역 공간, 함수 등이 있고 흔히 실행 컨텍스트를 구성하는 방법은 함수를 실행하는 것뿐이다.

콜 스택(Call Stack)

콜 스택에 실행 컨텍스트가 어떤 순서로 쌓이는지 알아보도록 하자.

// ------- (1)
var a = 1; 
function outer(){ 
  function inner(){ 
    console.log(a); 
    var a = 3; 
  } 
  inner(); // ------- (2)
  console.log(a); 
} 
outer(); // ------- (3)
console.log(a);
  1. 자바스크립트 코드가 실행되는 순간 전역 컨텍스트가 콜 스택에 담긴다. 별도의 실행 명령이 없어도 자바스크립트 파일이 열리는 순간 전역 컨텍스트가 활성화됨

  2. (3)에서 outer 함수를 호출하면 자바스크립트 엔진이 outer에 대한 환경 정보를 수집해서 outer 실행 컨텍스트를 생성한 후 콜스택에 담는다. 콜스택 맨 위에 outer 실행 컨텍스트가 있으므로 전역 컨텍스트 실행을 멈추고 outer 함수 내부의 코드들을 순차로 실행

  3. (2)에서 inner 함수의 실행 컨텍스트가 콜 스택의 가장 위에 담기기 때문에 outer 컨텍스트와 관련된 코드 실행을 멈추고 innter 함수 내부의 코드를 순서대로 진행

  4. inner 함수 내부에서 a 변수에 값 3을 할당하고 inner 함수의 실행이 종료되면서 콜 스택에서 제거

  5. outer 컨텍스트가 콜 스택의 맨 위에 있으므로 (2)의 다음 줄부터 실행 변수 a의 값을 출력하고 outer 함수 실행 종료, outer 실행컨택스트 콜 스택에서 제거

  6. 콜 스택에 전역 컨텍스트만 남게 됨, 실행을 중단했던 (3)의 다음 줄부터 실행 a 변수 값 출력 후 전역 공간에 실행할 코드가 남아 있지 않아 전역 컨텍스트 제거

  7. 콜 스택에 아무것도 남지 않은 상태로 종료

실행 컨텍스트의 수집 정보

VariableEnvironment

현재 컨텍스트 내의 식별자들에 대한 정보 + 외부 환경 정보, VariableEnvironment에 담기는 내용은 LexicalEnvironment와 같지만 최초 실행 시의 LexicalEnvironment의 스냅샷으로 변경 사항은 반영되지 않는다.

LexicalEnvironment

실행 컨텍스트 생성 시 VariableEnvironment에 정보를 먼저 담은 다음, VariableEnvironment를 복사 후 LexicalEnvironment를 만든다. LexicalEnvironment을 주로 활용하고 둘의 내부는 environmentRecord 와 outer-EnvironmentReference로 구성되었다.

environmentRecord와 호이스팅(hoisting)

호이스팅 전

funtion a (x) {
  console.log(x); 
  var x;
  console.log(x); 
  var x = 2;
  console.log(x); 
}
a(1)

호이스팅 후

funtion a (x) {
  var x;
  var x;
  var x;
  
  x = 1;
  console.log(x); // 1
  console.log(x); // 1
  x = 2;
  console.log(x); // 2
}
a(1)

environmentRecord에는 현재 컨텍스트와 관련된 코드의 식별자 정보들(매개변수의 이름, 함수 선언, 변수명 등)이 저장되고 컨텍스트 내부 전체를 처음부터 끝까지 훑어나가며 순서대로 수집한다. 그래서 코드가 실행되기 전임에도 자바스크립트 엔진이 해당 환경에 속한 코드의 변수명을 모두 알고 있는 것이다. 여기서 호이스팅(hoisting)이라는 개념이 등장한다. 호이스팅이란 자바스크립트 엔진이 식별자들을 최상단으로 끌어올려 놓는 것을 말한다.

함수 선언문과 함수 표현식

호이스팅 전

console.log(sum(1, 2));
console.log(multiply(3, 4));

funtion sum (a, b) { // 함수 선언문
  return a + b;
}

var multiply = funtion (a, b) { // 함수 표현식
  return a * b;
}

호이스팅 후

funtion sum (a, b) { // 함수 선언문 전체를 호이스팅
  return a + b;
}
var multiply; // 변수는 선언부만 호이스팅

console.log(sum(1, 2));
console.log(multiply(3, 4));

multiply = funtion (a, b) { // 변수의 할당부는 원래 자리
  return a * b;
}

함수 선언문(Function Dgeclaration)과 함수 표현식(Function Expression)이 environmentRecord의 정보 수집 과정에서 발생하는 호이스팅을 살펴보도록 하자. 함수 선언문은 전체를 호이스팅한 반면 함수 표현식은 변수 선언부만 호이스팅을 한다. 이유는 함수도 하나의 값으로 취급하기 때문이다.

스코프, 스코프 체인, outerEnvironmentReference

스코프(scopr)란 식별자에 대한 유효범위이고, 식별자의 유효범위를 안에서부터 바깥으로 차례로 검색해나가는 것을 스코프 체인(scope chain) 이라고 한다. 그리고 이를 가능케 하는 것이 바로 LexicalEnvironment의 두 번쨰 수집 자료인 outerEnvironmentReference 이다.

스코프 체인

var a = 1; 
function outer(){ 
  function inner(){ 
    console.log(a); // undefined 
    var a = 3; 
  } 
  inner(); 
  console.log(a); // 1 
} 
outer(); 
console.log(a); // 1

outerEnvironmentReference는 현재 호출된 함수가 선언될 당시의 LexicalEnvironment를 참조한다. A 함수 내부에 B 함수를 선언하고 다시 B 함수 내부에 C 함수를 선언한 경우, 함수 C의 outerEnvironmentReference는 함수 B의 LexicalEnvironment를 참조한다. 함수 B의 LexicalEnvironment에 있는 outerEnvironmentReference는 함수 B가 선언되던 때 A의 LexicalEnvironment를 참조한다. 이처럼 outerEnvironmentReference는 연결 리스트(linked list) 형태를 띤다. 선언 시점의 LexicalEnvironment를 계속 찾아 올라가면 마지막엔 전역 컨텍스트의 LexicalEnvironment이 있고 각 outerEnvironmentReference는 오직 자신이 선언된 시점의 LexicalEnvironment만 참조 가능하므로 가장 가까운 요소부터 차례대로만 접근 가능하다. 이런 구조적 특성 덕분에 여러 스코프에서 동일한 식별자를 선언해도 무조건 스코프 체인 상에서 가장 가까운 식별자에만 접근 가능하다

전역변수와 지역변수

  • 전역변수(global variable)는 전역 컨텍스트의 LexicalEnvironment에 담긴 변수를 전역 변수라 하고 전역 스코프에서 선언한 a와 outer 둘이다.
  • 지역변수(local variable)는 함수에 의해 생성된 실행 컨텍스트의 변수들을 지역변수라 하고 outer 함수 내부에서 선언한 inner와 inner 함수 내부에서 선언한 a 둘이다.
profile
늘 한결같이 꾸준히

0개의 댓글