[JavaScript] 실행 컨텍스트 및 콜스택

실행 컨텍스트

실행할 코드에 제공할 환경정보들을 모아둔 객체

JS는 특정 실행 컨텍스트가 활성화되기 전 다음을 수행한다.

  • 선언된 변수 호이스팅
  • 외부 화경 정보를 구성
  • this값 설정

 

콜스택 (Call stack)

동일한 환경에 있는 코드를 실행할 때 필요한 환경 정보들을 모아 컨텍스트를 구성하고 이를 콜스택에 쌓아올린다.

가장 위에 쌓여있는 컨텍스트와 관련된 코드를 실행하는 방법으로 코드의 환경 및 순서를 보장하는 것.

 

실행 컨텍스트의 구성 정보

VariableEnvironment (VE)

1) 현재 컨텍스트 내의 식별자 정보(record)를 갖고 있다.

ex. var a = 3 에서 var a

 

2) 외부 환경 정보 (outer)를 갖고있다.

 

3) 선언 시점 LexicalEnvironment의 snapshot

-> 즉, 변경사항을 반영하지 않는다.

LexicalEnvironment (LE)

VE는 실행 컨텍스트가 최초 생성됐을 때의 값을 계속 유지하고, LE는 같은 정보를 갖고있지만 변경사항이 있을 때 변경된다.

따라서 실행 컨텍스트가 생성된 최초의 순간에는 VE와 LE가 갖고있는 값이 같다.

실행 컨텍스트를 생성할 때 VE에 먼저 정보를 담은 다음, 이를 그대로 복사해서 LE에 담고 실시간으로 업데이트 하면서 활용한다.

 

ThisBinding

 

record와 호이스팅

변수 정보 수집을 이해하기 쉽게 설명한 가상 개념이다.

 

호이스팅 규칙

1. 매개변수 및 변수는 선언부를 호이스팅 한다. 

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

a();

 

두번째 console.log에서 undefined가 출력될 것이라 예상하기 쉽지만 1이 출력된다. 변수의 선언부를 모두 위로 끌어올리기 때문이다. 

 

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

a();

이와같이 동작하는 것이다.

 

2. 함수 선언은 전체를 호이스팅 한다.

function a() {
    console.log(b);  // [Function : b]
    var b = 'bbb';
    console.log(b);  // bbb
    function b() { }
    console.log(b);  // bbb
}

a();

첫 console.log에서 선언되지 않은 것을 출력하려해 오류가 발생할 것이라 예상할 수 있다. 하지만 호이스팅으로 아래와 같이 동작하게된다.

function a() {
    var b;
    function b() { }
    console.log(b);
    b = 'bbb';
    console.log(b);
    console.log(b);
}

a();

 

 

// 함수 선언문
console.log(sum(1, 2));
console.log(multiply(3, 4));  // 오류 발생

function sum (a, b) {
	return a + b;
}

var multiply = function (a, b) { 
	return a * b;
}


// ---------------- 호이스팅 -----------------

function sum (a, b) {
	return a + b;
}

var multiply; 

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

multiply = function (a, b) {
	return a * b;
};

함수 선언시 전체가 호이스팅 되는 경우는 함수 선언문을 사용한 경우이고, 함수 표현식으로 함수를 선언한 경우에는 식별자만 호이스팅 된다. 따라서 위의 경우는 multiply가 아직 초기화되지 않은 상태로 함수를 호출하자 오류를 발생시키는 것이고, 이 말은 함수 표현식으로 함수를 선언할 경우 프로그래머가 작성한 선언문 이후로만 영향을 미칠 수 있다는 것이다.

 

console.log(sum(1, 2));  // 6

function sum (a, b) {
	return a + b;
}

// 생략

function sum (a, b) {
    return a * 2 + b * 2;
}

함수 표현식과 호이스팅의 특징은 협업 과정에서 유용하게 활용될 수 있다. 협업시에는 함수 표현식을 활용하는 것을 추천한다. 위처럼  같은 이름의 함수가 이미 사용되고있다는 것을 모르고 새로운 함수를 선언하는 경우 새로운 sum을 선언하기 이전의 동작들에까지 영향을 미치게되기 때문이다.

 

 

스코프 체인과 outer

outer

현재 호출된 함수가 선언될 당시의 LexicalEnvironment를 참조한다.

즉 function a() 내부에 function b()가 선언되어있다면, b는 자신이 선언된 시점에서 a함수의 LE를 outer로 갖게되는 것이다.

타고 올라가다보면 전역 컨텍스트를 참조하게 되지만, outer는 자신이 선언된 시점의 LE를 참조하고 있으므로 가장 가까운 요소부터 차례대로 접근하게 된다.

스코프 체인

각 실행 컨텍스트는 LE에 record와 outer를 가지고있으며, outer 안에는 그 실행 컨텍스트가 선언될 당시의 LE 정보가 모두 들어있다.

따라서 스코프 체인에 의해 상위 컨텍스트의 record를 읽어올 수 있게 된다!