main-logo

실행 컨텍스트

실행 컨텍스트를 알아보자

profile
1320129
2023년 08월 20일 · 0 분 소요

들어가며

안녕하세요 오늘은 javascript에 실행 컨텍스트를 같이 알아볼까요?
클로저(closure), 스코프(scope)에 대해 좀 더 이해를 쉽게 만들어주는 지식이기도 합니다.
하지만 직접 확인하기가 어렵고 추상적인 내용이라 지루해서 대충 보고 까먹는 경우가 많은데요 이번 기회에 같이 확인해 보아요.

실행 컨텍스트란?


실행 컨텍스트(Execution Context)는 자바스크립트 코드의 실행 순서와 그 환경을 관리하는데 필요한 정보를 담고 있는 실행 환경입니다.
자바스크립트 엔진은 함수 호출, 문장의 실행 등 코드를 해석하고 처리하기 위해 실행 컨텍스트를 생성 및 관리합니다.
이 과정은 눈에 보이지 않지만, 자바스크립트 엔진은 매우 효율적이고 바쁘게 움직이고 있습니다~!
실행 컨텍스트를 이해하기 위해서는 몇 가지 알아둬야 할 개념들이 있습니다! 함께 살펴볼까요?

콜 스택


콜 스택(Call Stack)은 실행 컨텍스트들이 쌓이는 자료구조로, 중요한 역할을 합니다!
콜 스택은 LIFO(Last In, First Out) 방식으로 동작합니다.
즉, 가장 나중에 들어간 항목이 가장 먼저 나오는 구조입니다.
좀 더 복잡한 구조이지만 이해를 돕기 위해 프링글스 통 안에 코드의 실행 컨텍스트들이 차곡차곡 쌓인다고 생각하시면 좋습니다!

 

image1.jpg

(먹고싶다...)

호이스팅


코드가 실행되면, 먼저 전역 실행 컨텍스트가 콜 스택에 만들어집니다!
전역 실행 컨텍스트는 환경 레코드(Environment Record)를 참조하게 되고요.
실행 컨텍스트에 대해 잘 모르신다면 약간 혼란스러우시죠? ㅎㅎ..

 

실행 컨텍스트에서 호이스팅과 관련 있는 부분은 바로 환경 레코드입니다.
호이스팅은 크게 2가지로 나뉘게 되는데요.
변수 호이스팅과 함수 호이스팅입니다.

변수 호이스팅


먼저 변수 호이스팅에 대해서 알아보겠습니다.
대부분 알고 있는 변수 let, const, var로 설명하자면

 

console.log(test); // undefined
var test = '날 호출해!';
console.log(test); // 날 호출해!

해당 코드를 실행 컨텍스트로 살펴보겠습니다!
맨 처음 콜 스택에는 전체 코드를 먼저 스캔하고 전역 선언문을 확인하여 환경 레코드에 test 변수를 저장하게 됩니다. 이 부분을 “생성 단계”라고 합니다.
하지만 var는 환경 레코드에 저장이 될 때 선언과 동시에 undefined로 자동 초기화 시켜주게 됩니다.
그래서 맨 처음 console.log는 아직 test에 값이 할당하기 전에 실행되어 undefined를 log에 찍어주고 콜 스택에서 pop 하게 됩니다.
해당 부분을 “실행 단계”라고 합니다. 그 이후에 test 변수에 값이 할당되고, “날 호출해!”를 그 이후에 log에 찍히는 거랍니다.

 

※console.log는 내장 메서드로서, 전역 객체에 속해있습니다. 따라서 환경 레코드에 별도로 저장되지 않습니다.

 

console.log(test); // ReferenceError
const test = '날 호출해!';
console.log(test); // 날 호출해!

그렇다면 let이나 const라면 어떨까요?
let, const는 변수 선언을 해주지만, var처럼 특정 값으로 초기화 시켜주지 않습니다.
따라서 let과 const 변수를 선언하기 전에 접근하려고 하면 ReferenceError가 발생하게 됩니다.

함수 호이스팅


함수를 호출하는 코드와 함수 선언이 있는 코드는 실행 순서에 따라 결과가 다르게 나타날 수 있습니다.
예를 들면, 함수 선언문은 다음과 같이 작성할 수 있습니다.

 

test();

function test() {
  console.log('첫 번째 예제');
}

위 코드는 정상적으로 실행되며, “첫 번째 예제”라는 출력을 볼 수 있습니다.
이는 호이스팅 때문입니다.
현재 실행 컨텍스트의 생성 단계에서 환경 레코드를 만들고, 이를 전부 스캔하여 선언문을 먼저 저장합니다.
이 과정에서 test 함수가 호이스팅되어 환경 레코드에 저장되고, 함수가 호출될 수 있게 됩니다.
하지만 자바스크립트에서는 함수를 변수에 할당하는 방식도 사용할 수 있는데요. 다음 예시를 보겠습니다.

 

currentTest();

var currentTest = function test() {
  console.log('두 번째 예제');
};

이 경우, “currentTest is not a function” 오류 메시지가 발생합니다.
이유는 무엇일까요? currentTest를 var 키워드로 선언했기 때문에 호이스팅 과정에서 currentTest는 undefined로 초기화됩니다.
그리고 함수를 호출하기 전에 함수를 할당받지 못했기 때문에 오류가 발생하게 됩니다.
호이스팅은 자바스크립트에서 흥미로운 개념이네요 ㅎㅎ

전역 실행 컨텍스트는 환경 레코드(Environment Record)를 참조하고 거기에 호이스팅 지식이 필요하기에 설명을 드렸습니다.
이를 이해하면 실행 컨텍스트의 동작 원리를 더 잘 이해할 수 있습니다!

외부 환경 참조


외부 환경 참조는 상위 렉시컬 환경에 대한 참조를 말합니다!
저번 스코프에서 말씀드렸던 스코프 체인과도 매우 관련이 큰 내용이기도 합니다.

 

환경 레코드(Environment Record), 외부 환경 참조(Outer Environment Reference)를 묶어 렉시컬 환경(Lexical Environment) 라 지칭합니다!

const 콜라 = ‘마셔!’;

function 이층() {
  const 물 = ‘마셔!;
    console.log( 소주); // 레퍼런스 에러  — 못마심
  function 삼층() {
    const 소주 = ‘마셔!’;
    console.log(콜라, 물, 소주);
  }

  삼층();
}

이층();
image2.png

이 예시에서 일층(전역 렉시컬 환경)에는 콜라가 있고, 이층(이층 함수의 렉시컬 환경)에는 물이 있으며, 삼층(삼층 함수의 렉시컬 환경)에는 소주가 있습니다.
이 외부 환경 참조에 의해 삼층에서는 콜라, 물, 소주를 전부 마실 수 있어요!
하지만 이층에서 삼층에 있는 소주를 마시려 하면 레퍼런스 에러가 발생합니다.
아래층에서는 위층에 있는 음료를 마실 수 없습니다.
이렇게 외부 환경 참조를 통해 상위 스코프의 변수나 함수에 어떻게 접근하는지 이해할 수 있습니다!
자바스크립트에서 특정 스코프에서 변수나 함수를 어떻게 사용하는지 결정하는 것을 식별자 결정이라고 합니다!
저희는 현재 층에서 무엇을 마실 수 있는지 결정한다고 생각하면 편할 것 같네요.

마치며

오늘은 실행 컨텍스트에 대해 함께 알아보았습니다.
실행 컨텍스트의 내용이 매우 방대하다 보니 추가적으로 더 궁금하다 왜 저렇게 작동하는 거지? 라는 의구심이 생길 수도 있습니다.
그렇다면 좀 더 추가적으로 공부할 수 있는 좋은 기회라고 생각합니다.ㅎㅎ!
긴 글 읽어주셔서 감사합니다!