[JavaScript 문법] 실행컨텍스트(VE, LE, ecord, 호이스팅, outer, 스코프)

조아영·2024년 7월 25일

📌

자바스크립트의 실행 컨텍스트는 실행할 코드에 환경 정보들을 모아놓은 객체입니다.
자바스크립트는 어떤 실행 컨텍스트가 활성화되는 시점에 다음과 같은 일을 합니다.

  • 선언된 변수를 위로 끌어올림 = 호이스팅(hoisting)
  • 외부 환경 정보를 구성
  • this 값을 설정

◼ 실행 컨텍스트란?

1. 스택, 큐

스택(Stack)

Last in, first out(LIFO)
마지막으로 들어간 것이 처음으로 나온다.
예시) 바구니에 쌓이는 책. 마지막에 넣은 책이 제일 위에 있어 제일 먼저 꺼낼 수 있다.

큐(Queue)

First in, first out(FIFO)
처음 들어간 것이 처음으로 나온다.
예시) 원통에 넣는 책. 처음 넣은 책이 아래로 제일 먼저 빠진다.

2. 콜 스택(call stack)

동일 환경에 있는 코드를 실행할 때 필요한 환경 정보들을 모아 컨텍스트를 구성하고 이것을 스택의 한 종류인 콜스택에 쌓아올립니다.
가장 위에 쌓여있는 컨텍스트와 관련된 코드를 실행하는 방법으로 코드의 환경 및 순서를 보장할 수 있습니다.

실행컨텍스트 구성방법

  • 전역공간
  • eval()함수
  • 함수

실행컨텍스트 구성순서

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

// undefined 1 1

코드실행 → 전역(in) → 전역(중단) + outer(in) → outer(중단) + inner(in) → inner(out) + outer(재개) → outer(out) + 전역(재개) → 전역(out) → 코드종료

특정 실행 컨텍스트가 생성되는(활성화되는) 시점은 콜 스택의 맨 위에 쌓이는(노출되는) 순간을 의미합니다.
즉, 현재 실행할 코드에 해당 실행 컨텍스트가 관여하게 되는 시점을 의미합니다.

3. 실행 컨텍스트 객체에 담기는 정보

VariableEnvironment(VE)

  • 현재 컨텍스트 내의 식별자 정보(=record)를 갖고있습니다.
    var a = 3에서 var a를 의미
  • 외부 환경 정보(=outer)를 갖고있습니다.
  • 선언 시점 LexicalEnvironment의 snapshot(최초의 모습)

LexicalEnvironment(LE)

  • VariableEnvironment와 동일하지만, 변경사항을 실시간으로 반영합니다.

ThisBindings

  • this 식별자가 바라봐야할 객체

◼ VE, LE

VE와 LE에 담기는 항목은 완벽하게 동일합니다. 스냅샷 유지여부에만 차이점이 있습니다.
VE : 스냅샷(최초의 모습)을 유지합니다.
LE : 스냅샷(최초의 모습)을 유지하지 않습니다. 즉, 실시간으로 변경사항을 반영합니다.

결국, 실행 컨텍스트를 생성할 때, VE에 정보를 먼저 담은 다음, 이를 그대로 복사해서 LE를 만들고 이후에는 주로 LE를 활용합니다.

1. 구성 요소

VE, LE의 구성 요소는 모두 동일하며, "environmentRecord"와 "outerEnvironmentReference"로 구성됩니다.

environmentRecord(=record)

  • 현재 컨텍스트와 관련된 코드의 식별자 정보들이 저장됩니다.
  • 수집 대상 정보 : 함수에 지정된 매개변수 식별자, 함수자체, var로 선언된 변수 식별자 등

outerEnvironmentReference(=outer)

  • 스코프 체인이 가능토록 하는 것(외부 환경의 참조정보)

◼ environmentRocord(= record), 호이스팅

  • 현재 컨텍스트와 관련된 코드의 식별자 정보(var a)들이 저장(기록=record)됩니다.
  • 수집 대상 정보 : 함수에 지정된 매개변수 식별자, 함수 자체, var로 선언된 변수 식별자 등
  • 컨텍스트 내부를 처음부터 끝까지 순서대로 훑어가며 수집합니다.
  • 순서대로 수집할뿐, 코드가 실행되지는 않습니다.
  • record의 수집과정이 hoisting입니다.

1. 호이스팅(hoisting = 끌어 올리기)

  • 변수정보 수집을 모두 마쳤더라도 아직 실행 컨텍스트가 관여할 코드는 실행 전의 상태입니다.(JS 엔진은 코드 실행 전 이미 모든 변수정보를 알고 있는 것)
  • 호이스팅이란, 변수 정보 수집 과정을 이해하기 쉽게 설명한 가상 개념입니다.

2. 호이스팅 규칙

호이스팅 법칙 1

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

적용 전

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

예상 : 1, undefined, 2

매개변수 적용

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

호이스팅 적용

function a() {
    var x;
    var x;
    var x;

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

실제 : 1, 1, 2

호이스팅 법칙 2

함수 선언은 전체를 호이스팅합니다.

적용 전

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

예상 : 에러(또는 undefined), "bbb", b함수

호이스팅 적용

function a () {
    var b; // 변수 선언부 호이스팅
    function b() { } // 함수 선언은 전체를 호이스팅
    console.log(b);
    b = "bbb"; // 변수의 할당부는 원래 자리에
    console.log(b);
    console.log(b);
}
a();

함수선언문 → 함수표현식

function a () {
    var b; // 변수 선언부 호이스팅
    **var b = function b() { } // 함수 선언은 전체를 호이스팅
    console.log(b);
    b = "bbb"; // 변수의 할당부는 원래 자리에
    console.log(b);
    console.log(b);
}
a();

실제 : b함수, "bbb", "bbb"

3. 함수 선언문, 함수 표현식

함수 정의의 3가지 방식

1. 함수 선언문

함수명 a가 곧 변수명. function 정의부만 존재, 할당 명령이 없는 경우

function a() {
/* ... */
}
a(); // 실행 O

2. 함수 표현식

정의한 function을 별도 변수에 할당하는 경우

2-1. 익명 함수 표현식

변수명 b가 곧 변수명(일반적인 케이스)

var b = function () {
/* ... */
};
b(); // 실행 O

2-2. 기명 함수 표현식

변수명은 c, 함수명은 d. d()는 c() 안에서 재귀적으로 호출될 때만 사용 가능하므로 사용성에 대한 의문이 있습니다.

var c = function d() {
/* ... */
};
c(); // 실행 O
d(); // 에러

주의해야 할 내용

적용 전

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;
};

호이스팅 적용

LE는 record와 outer를 수집하고 record를 수집하는 과정에서 hoisting합니다.

// 함수 선언문 : 전체를 hoisting
function sum(a, b) {
    return a + b;
}

// 함수 표현식 : 변수는 선언부만 hoisting
var multiply; // 변수 선언부

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

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

◼ outerEnvironmentReference(=outer), 스코프, 스코프 체인

1. 주요 용어

스코프

  • 식별자에 대한 유효범위를 의미합니다.
  • 대부분 언어에 존재, JS에서도 존재합니다.

스코프 체인

  • 식별자의 유효범위를 안에서부터 바깥으로 차례로 검색해나가는 것

outerEnvironmentReference(=outer)

스코프 체인이 가능토록 하는 것(외부 환경의 참조정보)

2. 스코프 체인

  • outer는 현재 호출된 함수가 선언될 당시의 LexicalEnvironment를 참조합니다. 그 당시의 환경 정보를 저장하는 것을 의미합니다.
  • 항상 outer는 오직 자신이 선언된 시점의 LexicalEnvironment를 참조하고 있으므로, 가장 가까운 요소부터 차례대로 접근이 가능합니다.
  • 스코프 체인 상에서 가장 먼저 발견된 식별자에게만 접근이 가능합니다.
var a = 1;
var outer = function () {
    var inner = function () {
        console.log(a); // undefined
        var a = 3;
    };
    inner();
    console.log(a); // 1
};
outer();
console.log(a); // 1

각각의 실행 컨텍스트는 LE 안에 recordouter를 가지고 있고,
outer 안에는 그 실행 컨텍스트가 선언될 당시의 LE정보가 들어있으니 scope chain에 의해 상위 컨텍스트의 record를 읽어올 수 있습니다.

0개의 댓글