내가 찾아가는 JavaScript_실행 컨텍스트(中)

Daniel Woo·2022년 4월 2일
0
post-thumbnail

실행 컨텍스트는 자바스크립트 엔진의 동작원리인 만큼 그 내용이 방대하다. 이전 글에서는 실행 컨텍스트에 대한 간단한 소개와 소스코드의 평가와 실행에 대해 정리했으니, 이번 글에서는 실행 컨텍스트가 어떠한 역할을 담당하는지, 자바스크립트 코드는 어떤 순서대로 실행되고, 값이 저장되는지 알아보려고 한다.

만약 이전 글 - 실행 컨텍스트(上)을 보지 못했다면 참고하세요 😉
내가 찾아가는 JavaScript_실행 컨텍스트(上)

실행 컨텍스트의 역할

// 전역 변수 선언
const x = 4;
const y = 2;

// 함수 선언
function global(argument) {
// 지역 변수 선언
	const x = 10;
    const y = -10;
    
    // 메서드 호출
    console.log(argument + x + y);
}

// 함수 호출
global(40);

// 메서드 호출
console.log(x + y);

위 코드는『모던 자바스크립트 딥다이브』p.362, [예제 23-02]를 변형한 코드이다. 간단한 코드지만 이 코드를 분석하면서 실행 컨텍스트가 자바스크립트에서 어떠한 역할을 할 수 있는지 알 수 있을 것이다.

1. 전역 코드 평가

이전 글에서 알아봤듯이, 자바스크립트 엔진은 코드를 바로 실행하지 않고, 변수와 함수 등 선언문을 먼저 파악하는 평가 단계를 시작한다.

이 과정에서 선언문의 식별자를 key값으로 하여 스코프라는 곳에 저장을 한다. 이때 스코프는 해당 소스코드의 종류가 어떤 것인지에 따라 달라진다. 가령, 전역 소스코드인 경우 전역 스코프, 함수 소스코드인 경우 해당 함수의 함수 스코프가 된다.

이 과정에서 식별자가 변수인 경우는 JS 엔진이 기본으로 값을 undefined로 초기화한다. 이와 같이 JS엔진이 코드가 실행되기 전, 즉 런타임 이전 코드를 한 번 훑는 과정에 의해 식별자를 관리하는 스코프가 생성되고, 이것이 호이스팅을 발생되는 이유이다.

호이스팅
코드의 위치와 관계 없이 이미 선언된 것처럼 동작하는 자바스크립트의 특징, 런타임 이전 소스코드 평가 단계를 거치기 때문에 발생한다.

위 코드에서는 전역 변수 x, y와 전역 함수인 global이 전역 스코프에 등록된 뒤 변수가 undefined로 초기화 된다.

2. 전역 코드 실행

스코프에 식별자 등록을 마쳤다면, JS엔진은 소스 코드를 실행하면서 변수의 값을 할당하거나 함수를 만나면 함수를 호출한다.

지금의 경우는 x, y의 값을 각각 4, 2로 재할당 시킨뒤 가장 먼저 만나는 함수인 global(40)을 호출한다.

3. 함수 코드 평가

함수를 호출한 경우 JS의 동작은 함수 호출 코드 다음으로 넘어가지 않고 호출한 함수의 내부로 실행 순서를 변경시킨다. 즉, global함수의 내붕에 대한 코드 평가가 이루어진다.

함수 내부에 있는 지역 변수 또는 다른 내부 함수의 선언문 등을 참조하여 다시 스코프에 등록한다. 지금은 함수 내부에서 코드 평가가 이루어졌기 때문에 스코프는 해당 함수의함수 스코프가 된다.

함수 코드 평가는 전역과는 다른 점이 있다면 함수의 인자로 받아지는arguments를 하나의 식별자로서 등록한다는 것이다. 즉, global 함수에서는 argument를 지역 변수인 x, y처럼 참조할 수 있다.

4. 함수 코드 실행

코드 평가가 끝나고 함수의 스코프가 형성되면 다시 함수 내부의 코드를 실행한다. global함수 내부에서 undefined로 초기화 됐던 x, y가 10, -10으로 값을 재할당받고 console.log()메서드가 호출된다.

console.log()메서드도 함수이기 때문에 다시 그 함수로 진입하여 코드 평가와 실행을 거친다. console 은 코드 어디에서든 참조할 수 있는 전역 객체이며, log()는 그 객체에 속해 있는 메서드이다.

메서드는 인자로 받은 argument + x + y 를 이전 스코프에서 참조하여 결과 값을 콘솔 창에 반환할 것이다.

    console.log(argument + x + y); // 40

이처럼 소스 코드 진행되고 각각의 실행 컨텍스트를 구성하는 과정을 보니 스코프를 실행 컨텍스트에 따라 구분하여 관리하고, 상위 스코프를 참조하는 것특정 원리에 따라 코드의 실행 순서가 변경되는 점을 발견할 수 있었다. 그리고 이것이 실행 컨텍스트가 JS에서 담당하는 역할이다. 정리하면 다음과 같다.

① 식별자 스코프 생성 및 관리
② 스코프 체인 → 상위 식별자 검색
③ 실행중인 코드 순서 변경

위에서 ①번과 ②번은 렉시컬 환경이라는 곳에서 관리하게 된다. 또한, 순서를 담당하는 ③번은 실행 컨텍스트 스택이라는 stack 자료구조에서 처리를 담당한다.
// 실행 컨텍스트 개념에는 여러 가지 자료구조 형태가 나오는데 가볍게라도 알아두면 좋을 것 같아서 자료구조의 종류를 참고하였다.

실행 컨텍스트 스택(call stack)

stack이라는 자료구조를 띠는 실행 컨텍스트 스택은 해당 자료구조의 특성상 가장 마지막 요소 (가장 최근 요소)부터 처리하는 LIFO (Last In First Out) 메커니즘은 가지고 있다.

무거운 상자를 보관하는 상황에서 기존 상자 위에 쌓아 올리고, 가장 위에 있는 것 부터 내리는 것 처럼 실행 컨텍스트는 가장 나중에 들어온 것이 가장 우선순위가 높은 것이 된다. 이렇게 실행 컨텍스트 스택에 최상단에 위치하는 실행 컨텍스트실행 중인 실행 컨텍스트라고 한다.

실행 중인 실행 컨텍스트
실행 순서를 처리하는 실행 컨텍스트 스택에서 코드가 실행되고 있는 실행 컨텍스트, 다른 실행 컨텍스트보다 나중에 스택에 포함되었다.

우리의 코드에서는 실행 컨텍스트 스택이 비어있다가 전역 실행 컨텍스트 위에 global 함수 실행 컨텍스트, log 함수 실행 컨텍스트가 쌓이고 가장 위에 있는 실행 컨텍스트 부터 처리하면서 실행 순서를 전환할 것이다.

실행 컨텍스트 스택

렉시컬 환경

렉시컬 환경은 실행 컨텍스트식별자와 식별자에 바인딩된 값 그리고 상위 스코프에 대한 참조를 관리하기 위해 만들어진다.

다시 렉시컬 환경은 환경 레코드(Environment Record)외부 렉시컬 환경(OuterLexicalEnvironmentReference)로 구성되어 있다. 전자는 식별자를 등록 및 바인딩 값을 관리하기 위한 것이고, 후자는 상위 스코프를 참조하는 스코프 체인을 저장한다.

렉시컬 환경

마치며

다음 글에서는 환경 레코드 생성과 this 바인딩 등 실행 컨텍스트의 깊이 있는 개념을 정리해볼 것이다. 자바스크립트를 더 깊이 있게 알아가는 과정이라고 생각하여 기대가 된다.

profile
모두가행복한세상을만들고싶은사람

0개의 댓글