[JavaScript] 실행 컨텍스트 구조(스코프 체인, 호이스팅 & this 바인딩)

Februaar·2024년 7월 15일
1

JavaScript

목록 보기
5/6
post-thumbnail

이전 포스트에서 실행 컨텍스트에 대해 정리한 적이 있다. 실행 컨텍스트는 스택 구조를 기반으로 작동하며, 콜 스택의 맨 위에 쌓인 실행 컨텍스트가 현재 실행 중인 코드에 관여하게 된다. 이는 새로 쌓인 컨텍스트가 기존의 컨텍스트 위에 위치하기 때문에 가능한 구조다.

어떤 실행 컨텍스트가 활성화되면, 자바스크립트 엔진은 해당 컨텍스트에서 코드를 실행하기 위해 필요한 환경 정보들을 수집하여 실행 컨텍스트 객체에 저장한다. 이 객체는 엔진이 활용하기 위한 용도로 생성되며, 개발자가 이를 직접 확인할 수는 없다. 따라서 실행 컨텍스트의 구조를 이해하는 것이 자바스크립트의 동작 방식을 깊이 파악하는 데 매우 중요하다.


💡실행 컨텍스트의 구성 요소

실행 컨텍스트는 자바스크립트 코드가 실행되는 환경을 구성하는 핵심 요소이다. 이를 통해 변수, 함수, 그리고 this의 동작 방식을 이해할 수 있다.

📌 변수 환경(Variable Environment)

VariableEnvironment는 실행 컨텍스트가 처음 생성될 때, 해당 컨텍스트에서 사용할 변수와 함수 선언에 대한 초기 스냅샷을 저장한다. 이후 LexicalEnvironment를 주로 사용하지만, VariableEnvironment는 최초 실행 시점의 상태를 유지하며, LexicalEnvironment는 그 후에 변경되는 동적인 값을 반영한다.

  • Environment Record: 변수 환경 레코드는 현재 실행 컨텍스트 내에서 선언된 변수와 함수 선언들을 저장한다. 이때 저장되는 정보는 초기화 시점의 상태 이며, 함수 선언도 포함된다.
  • Outer Environment Reference: 외부 환경 참조는 현재 컨텍스트가 참조하는 상위 스코프 를 가리킨다. 이는 스코프 체인을 형성하는 데 중요한 역할을 한다.

📌 렉시컬 환경(Lexical Environment)

LexicalEnvironment는 실행 컨텍스트가 실행 중일 때, 코드가 참조하는 변수 들과 스코프 체인 에 대한 정보를 관리한다. 이를 통해 현재 컨텍스트와 외부 컨텍스트 간의 연결이 이루어진다.

  • Environment Record: 렉시컬 환경 레코드는 현재 실행 중인 코드의 스코프와 변수들을 관리한다. 이는 함수나 블록 내에서 사용되는 변수를 포함하며, 현재 컨텍스트의 상태를 반영한다.
  • Outer Environment Reference: 렉시컬 환경의 외부 환경 참조는 상위 스코프를 가리킨다. 이로 인해 스코프 체인이 형성되어, 현재 컨텍스트 내에서 찾을 수 없는 변수를 상위 스코프에서 찾을 수 있다.

📌 This 바인딩(This Binding)

this는 함수가 호출될 때 어떤 객체를 가리킬지를 결정하는 중요한 요소이다. 함수 호출 방식에 따라 this가 참조하는 객체가 달라지며, 이에 따라 함수 내에서 this의 값이 다르게 바인딩된다.

그렇다면 실행 컨텍스트의 구성 요소들이 실제 코드에서 어떻게 동작하는지 알아보려고 한다.


1. 스코프 체인과 Outer Environment Reference

📌 스코프 체인의 역할

  • 스코프 체인은 현재 실행 중인 코드에서 변수를 검색하기 위해 만들어진 연결 고리이다.
  • 렉시컬 환경의 Outer Environment Reference는 상위 스코프를 가리키며, 이를 통해 스코프 체인을 형성한다.
function outer() {
  const a = 1;
  function inner() {
    const b = 2;
    console.log(a + b); // 3
  }
  inner();
}
outer();

동작 과정을 보면,

  1. outer 함수가 호출되면 새로운 실행 컨텍스트가 생성된다.
  • 이 컨텍스트의 렉시컬 환경은 a: 1을 포함한다.
  1. inner 함수가 호출되면 또 다른 실행 컨텍스트가 생성된다.
  • inner의 렉시컬 환경에는 b: 2가 저장된다.
  • inner의 Outer Environment Reference는 outer의 렉시컬 환경을 참조한다.
  1. console.log(a + b)에서 a를 찾을 때, inner의 렉시컬 환경에서 없으므로 스코프 체인을 따라 outer의 렉시컬 환경에서 검색한다.

2. 호이스팅과 실행 순서

📌 호이스팅의 역할

  • 실행 컨텍스트는 코드 실행 전에 모든 변수와 함수 선언을 처리한다.
  • 선언된 변수와 함수는 VariableEnvironment에 저장되며, 이후 LexicalEnvironment에서 실행된다.
console.log(foo); // undefined
var foo = 10;

console.log(bar); // ReferenceError
let bar = 20;

baz(); // "Hello"
function baz() {
  console.log("Hello");
}

호이스팅이 일어나고 실제 코드 실행은 어떻게 동작하는지 예제 코드를 통해 확인해보자,

  1. 호이스팅 단계
  • var foo는 선언만 되어 undefined로 초기화된다.
  • let bar는 TDZ(Temporal Deep Zone)에 놓여 초기화되지 않는다.
  • function baz는 전체 함수 선언이 호이스팅 된다.
  1. 코드 실행 단계
  • 첫 번째 console.log(foo)foo의 초기 값 undefined를 출력한다.
  • 두 번째 console.log(bar)let 선언된 bar가 TDZ 상태에 있어 ReferenceError를 발생시킨다.
  • baz()는 함수 선언이 호이스팅되었으므로 호출이 가능한 것이다.

3. this 바인딩의 결정

📌 this 바인딩의 역할

  • 실행 컨텍스트는 함수 호출 방식에 따라 this의 값을 동적으로 결정한다.
const obj = {
  value: 100,
  method() {
    console.log(this.value); // 100
  },
};

function globalFunc() {
  console.log(this); // window (브라우저) 또는 global (Node.js)
}

obj.method();
globalFunc();
  1. 객체 메서드 호출
  • obj.method()에서 this는 메서드를 호출한 객체 obj를 바인딩한다.
  • 따라서 this.value100을 출력한다.
  1. 일반 함수 호출
  • globalFunc()에서 this는 전역 객체를 바인딩한다.
  • 브라우저에서는 window, Node.js에서는 global이 출력된다.


여기서 핵심은 자바스크립트 엔진이 실제로 끌어올리지는 않지만 변수 정보를 수집하는 과정을 이해하기 쉬운 방법으로 호이스팅이라는 대체 가상의 개념을 만든 것이다. 그리고 함수는 함수 전체가 최상단으로 끌어올려진다고 했는데 함수 선언부 전체가 코드의 최상단으로 이동한다는 것을 의미하고, 이는 함수 이름과 함수 본체가 모두 호이스팅된다는 의미이다.

그렇기 때문에 함수가 정의된 위치에 상관없이 코드 어디에서든 해당 함수를 호출할 수 있게 된다. 이 부분에서 함수 선언함수 표현식이 다르게 호이스팅된다고 하는데 다음 장에 정리해보려고 한다.

profile
짱개발자가 되기 위한 개발기록 🐯

0개의 댓글