✈️ 실행 컨텍스트

2ㅣ2ㅣ·2024년 3월 26일

JavaScript

목록 보기
8/14
post-thumbnail

앞선 포스팅에서 자바스크립의 기초적인 개념들을 살펴봤다. 이번 포스팅에서는 JavaScript의 핵심 메커니즘 중 하나인 '실행 컨텍스트'를 학습하겠다. 이 개념은 JavaScript 코드가 어떻게 해석되고 실행되는지에 대한 근본적인 이해를 제공하며, 앞서 논의된 모든 주제들과 깊이 연결되어 있다. 실행 컨텍스트를 통해, 우리는 JavaScript의 실행 흐름을 보다 명확히 파악하고, 코드가 왜 그렇게 작동하는지에 대한 더욱 심오한 이해에 도달할 수 있다 🫡 ❣️ 🧗🏻‍♀️

실행 컨텍스트

  • 실행할 코드에 제공할 환경 정보들을 모아놓은 스택 구조 객체이다.
  • 한마디로 JavaScript 코드가 실행되는 환경이다.

스택과 큐

실행 컨텍스트는 스택의 구조를 따른다.

콜 스택

  • 실행 컨텍스트가 쌓이는 곳
  • 함수 호출 시 생성되는 실행 컨텍스트가 push되고 함수 실행 완료 후 pop되어 제거된다.
  • 전역공간, eval(), 함수 등으로 실행 컨텍스트를 구성할 수 있다.

다음 예시코드는 호이스팅에 의해 다음과 같이 동작한다.

var a = 1; 
function outer() {
  function inner() {
    console.log(a); //(1) undefined
    var a = 3;
  }
  inner();
  console.log(a); //(2) 1
}
outer();
console.log(a); //(3) 1
  • var a;선언됨
  • outer() 호출 후 outer() 내부에 있는 inner() 호출
  • inner() 내부에 var a; 선언됨
  • 할당 전 console.log(a); 는 초기화만 된 상태이므로 undefined
  • inner() 스코프 를 빠져나간 console.log(a); 는 전역 스코프 var a=1; 에 따라 1이 출력됨
  • outer() 스코프를 빠져나간 a도 동일한 동작으로 1 출력

만약 let,const로 선언하면? 🤔
let, const는 선언과 초기화가 독립적으로 발생하므로 TDZ에 걸려 참조 에러가 발생한다.

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

이를 콜스택에서 실행 컨텍스트가 어떻게 push, pop 되는지 시각화해보면 다음과 같다.

즉, 콜 스택 최상단에 위치한 컨텍스트가 현재 실행중인 컨텍스트임을 알 수 있다.

활성화된 실행 컨텍스트의 수집 정보

그렇다면 현재 실행 중인 컨텍스트는 어떻게 동작할까? 그 내부를 해부해보자.🚗 💨 💨

콜 스택에서 현재 실행 중인 컨텍스트, 즉 최상단에 위치한 실행 컨텍스트에는 VariableEnvironment, LexicalEnvironment, 그리고 this 바인딩과 같은 중요한 정보들이 담겨 있다. 이 정보들은 현재 실행 중인 코드가 어떻게 동작할지를 결정하는 데 핵심적인 역할을 한다.

  • VariableEnvironment 와 LexicalEnvironment
    변수와 함수 선언을 저장하는 데 사용된다. 이 두 환경은 실행 컨텍스트가 생성될 때 초기화되지만, LexicalEnvironment실행 도중에도 업데이트될 수 있다. 이는 let과 const로 선언된 변수들이나 함수 표현식이 실행 흐름에 따라 달라지기 때문입니다. VariableEnvironment는 주로 실행 컨텍스트 생성 시의 상태를 반영하며, 이후 변경되지 않는다.

  • LexicalEnvironment의 역할
    실행 컨텍스트에 속한 코드가 실행될 때 현재의 변수와 함수 선언에 대한 접근을 제어한다. LexicalEnvironment는 또한 외부 환경에 대한 참조도 포함하고 있어, 스코프 체인을 형성하고 변수를 찾을 때 이 스코프 체인을 따라서 검색할 수 있게 한다. ❗️컨텍스트를 구성하는 환경 정보들을 모아놓았다고 생각하면 쉽다❗️

실행 전 정보들을 VariableEnvironment와 LexicalEnvironment에 저장해놓는다는 것을 알게되었다. 그렇다면 우리가 지금까지 강조한 자바스크립트만의 고유한 특징인 호이스팅도 이러한 환경들에 저장되는 것일까? 코드 흐름에 따라 정보를 업데이트하는 LexicalEnvironment를 살펴보자.

EnvironmentRecord와 호이스팅 🍎

environmentRecord는 실행 컨텍스트의 LexicalEnvironment 구성 요소 중 하나로, 해당 스코프 내에서 선언된 모든 식별자(변수, 함수, 매개변수 등)와 그 값들을 저장한다. ❗️ 즉, 호이스팅 또한 LexicalEnvironment 그 중에서도 environmentRecord에 저장한다 ❗️

지금까지의 개념들로 실행 컨텍스트에 담기는 정보들을 도식화해보자.

위의 예시 코드를 기반으로 시각화했고, inner() 실행 컨텍스트가 활성화 된 시점이다.

호이스팅과 할당, 외부참조의 정보가 각각 어디에 담기는지 확인해보았다.

마지막으로 호이스팅의 예제 코드를 보면서 오늘 포스팅을 마무리하겠다.
👩🏼‍💻 개발자 관점

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

⚙️ 엔진 관점

function a() {
  var b;
  function b() {}
  console.log(b); // [Function: b]
  var b = 'bbb';
  console.log(b); // bbb
  console.log(b); // bbb
}
a();
  1. 실행 컨텍스트 생성
  • 함수 a()가 호출되면, JavaScript 엔진은 해당 함수에 대한 새로운 실행 컨텍스트를 생성.
    - 함수 a() 가 호출되기 전엔 전역 컨텍스트가 생성되어 있었음.
  • 이 실행 컨텍스트는 자신만의 VariableEnvironment와 LexicalEnvironment를 갖음.
  1. 호이스팅
  • 함수 선언(function b() {})변수 선언(var b;) 모두 실행 컨텍스트의 환경 레코드에 호이스팅됨.
  • 함수 선언이 변수 선언보다 높은 우선순위를 갖기 때문에, 초기 메모리 상태에서 b는 함수 b()를 가리킴.
  • 이 시점에서, b는 함수 객체를 참조함.
  1. 변수 할당
  • var b = 'bbb'; 코드가 실행되면서, 변수 b에 문자열 'bbb'가 할당됨.
  • 이 할당으로 인해 환경 레코드 내의 b의 참조가 함수 b()에서 문자열 'bbb'로 업데이트됨.
  • 이 시점부터 b는 더 이상 함수를 참조하지 않고 문자열 값을 가지게 됨.
  1. 코드 실행
  • 첫 번째 console.log(b);는 호이스팅으로 인해 함수 b()를 출력.
  • b에 'bbb' 할당 후, 두 번째 console.log(b);는 'bbb'를 출력.
  • 함수 선언 function b() {}은 이미 호이스팅 처리 되었으므로, 이후의 코드 실행에는 영향을 미치지 않음.
  • 세 번째 console.log(b);도 'bbb'를 출력.
  1. 실행 컨텍스트 종료
  • 함수 a()의 실행이 종료되면, a()의 실행 컨텍스트는 콜 스택에서 제거됨.
  • 이와 함께, a() 실행 컨텍스트 내에서 생성된 모든 변수와 함수 선언도 메모리에서 제거됨.
profile
https://sususoo.tistory.com/

0개의 댓글