[JavaScript]실행 컨텍스트란?

hyo·2023년 5월 29일
0

JS 심화 지식

목록 보기
1/2
post-thumbnail

시작하며

전부터 실행컨텍스트라는 단어를 몇번 들어보긴 하였는데, 찾아서 알아본 적은 없었다.
하지만 이번에 궁금하여 여기저기 구글링하며 강의도 들어보고 이해를 하게 되었다.
예전에 클로저, 호이스팅, 스코프에 대해서 공부를 하였었는데 실행컨텍스트를 이해하면 자바스크립트의 주요한 동작(클로저,호이스팅,스코프 등)의 원리를 더 잘 이해할 수 있게 된다.


실행컨텍스트 란?

실행 컨텍스트는 실행할 코드에 제공할 환경 정보들을 모아놓은 객체이다.
자바스크립트는 동일한 환경에 있는 환경 정보들을 모은 실행 컨텍스트를 콜스택에 쌓아올린 후 실행하여 코드의 환경과 순서를 보장할 수 있게 된다.

컨텍스트를 번역하면 문맥이다. 쉽게 코드의 실행 환경이라고 이해하면 된다.
쉽게 말해, 스택의 경우 FILO(First In, Last Out)인 선입후출의 구조이기에 순서를 보장, 콜스택 내부에 쌓인 실행 컨텍스트의 정보를 통해 환경을 보장할 수 있다.
-> 환경이란? 전역공간 혹은 함수 즉, 함수 내부의 환경

모든 자바스크립트 코드는 실행 컨텍스트 내부에서 실행 된다고 생각하면 된다!

즉 함수가 실행(브라우저가 스크립트를 로딩해서 실행하는 걸 의미) 되면 함수 실행에 해당하는 실행 컨텍스트가 생성되고, 자바스크립트 엔진에 있는 Call Stack에 차곡차곡 쌓인다.

실행 컨텍스트는 식별자(변수, 함수, 클래스 등의 이름)를 등록하고 관리하는 스코프와 코드 실행 순서 관리를 구현한 내부 매커니즘으로, 실행 컨텍스트는 곧 자바스크립트의 핵심 원리이다.

var str = 'hello';

function B() {
  console.log('안녕');
}
function A() {
  B();
}

A();

처음 자바스크립트 코드를 실행하는 순간 위 이미지의 (1)처럼 전역 컨텍스트가 콜스택에 담긴다.
브라우저의 경우 window, node 환경의 경우 global 같은 객체를 사용할 수 있는 이유이다.

  • (1) 콜스택엔 전역 컨텍스트를 제외하곤 다른 컨텍스트가 없기에 전역 컨텍스트와 관련된 코드를 진행.
  • (2) 전역 컨텍스트와 관련된 코드를 진행 중 A함수를 실행하였기에 A함수의 환경 정보들을 수집하여 A실행 컨텍스트를 생성, 콜스택에 담는다.
    콜스택 최상단에 A실행 컨텍스트가 있기에 기존의 전역 컨텍스트와 관련된 코드의 실행을 일시적으로 중단 후, A실행 컨텍스트의 코드를 실행.
  • (3) A함수 내부에서 B함수를 실행하였기에 B함수의 환경 정보들을 수집, B실행 컨텍스트 생성, 콜스택에 담는다.
    이전과 같이 콜스택 최상단에 B실행 컨텍스트가 있기에 기존 A실행 컨텍스트와 관련된 코드의 실행을 일시적 중단 후, B실행 컨텍스트의 코드를 실행.
  • (4) B함수가 종료된 후 B실행 컨텍스트가 콜스택에서 제거된다.
    제거 후 콜스택 최상단에는 A실행 컨텍스트가 있기에 이전에 중단된 지점부터 코드 진행이 재개된다.
  • (5) A함수 또한 종료된 후 A실행 컨텍스트가 콜스택에서 제거된다.
  • 이후엔 전역 공간에 실행할 코드가 남아있지 않다면 콜스택에서 전역 컨텍스트 또한 제거되며 콜스택에 아무것도 남지 않은 상태로 종료된다.



실행컨텍스트 구조

실행 컨텍스트 내부엔 Variable Environment, Lexical Environment, This Binding 가 있다.

VariableEnvironment

VariableEnvironment 란 현재 컨텍스트 내부의 식별자 정보(environmentRecord), 외부 환경 정보(outerEnvironmentReference)가 포함되어 있다.
VariableEnvironment에 먼저 정보를 담고, 그대로 LexicalEnvironment에 복사해 사용한다고 한다.

LexicalEnvironment

LexicalEnvironment 는 초기에는 VariableEnvironment 와 같지만 변경 사항이 실시간으로 적용 된다고 한다.
즉, VariableEnvironment는 초기 상태를 기억하고 있으며, LexicalEnvironment는 최신 상태를 저장하고 있다.

environmentRecord 환경레코드 (식별자 정보)

environmentRecord 란 현재 컨텍스트와 관련된 식별자와 식별자에 바인딩(할당)된 값이 기록되는 공간이다.
실행 컨텍스트 내부 전체를 처음부터 끝까지 확인하며 순서대로 수집한다.

아래에서 environmentRecord에 대해 더 알아보자.

var myName = 'hyo';
console.log(myName); // hyo

위는 정상적으로 hyo가 출력된다.
하지만 아래같은 경우를 보자.

console.log(myName); // undefined
var myName = 'hyo';

선언하기도 전에 값을 호출했는데 Reference Error가 발생하지 않고 undefined(할당되지 않음)가 출력된다.
이것은 자바스크립트의 호이스팅이라는 현상과 관련이 있다.

호이스팅 관련 포스팅 바로가기

결론

LexicalEnvironment의 environmentRecord 의 경우 해당 컨텍스트 환경에 필요한 식별자와 식별자의 값이 기록되고, 함수 실행 시 실행 컨텍스트가 생성되므로 (함수 실행보다 environmentRecord 수집이 먼저 되므로) 변수와 같은 식별자를 끌어올리는 것과 같다 라는 개념의 호이스팅이 생겨났다.

실행 컨텍스트의 생성 단계(creation phase)

Execution Context 생성
선언문만 실행해서 EnvironmentRecord에 기록!

자바스크립트 엔진은 코드를 실행하면 우선 전역 실행 컨텍스트 한 칸을 생성해서 콜스택에 넣는다.
그 후, 전체 코드를 스캔하며 선언할게 있는지 찾아보고 있다면 먼저 선언해 둔다.
선언하는 과정에는 생성해둔 실행컨텍스트 안에 있는 environmentRecord에 새로운 식별자(ex. a,b,str)를 기록한다.
그리고 var키워드로 선언했기때문에 undefined로 값을 초기화 해둔다.
이렇게 스캔하고 준비하는 단계를 생성 단계라고 한다.

-> 실행 컨텍스트를 생성하고, 선언문만 먼저 실행해서 환경레코드(EnvironmentRecord)에 미리 기록해두는 단계이다.

실행 컨텍스트의 실행 단계(execution phase)

선언문 외 나머지 코드 순차적 실행
EnvironmentRecord 참조하거나 업데이트


outerEnvironmentReference (외부 환경 정보)
const name = 'hyo';

const car = () => {
  const a = {
    brand: 'kia',
    name: 'sportage'
  };
  const b = {
    brand: 'hyundai',
    name: 'tucson'
  };
  console.log(name);
  console.log(a);
  console.log(b);
}

car(); // 'hyo', {brand: 'kia', name: 'sportage'}, {brand: 'hyundai', name: 'tucson'}
console.log(a); // ReferenceError: a is not defined
console.log(b); // ReferenceError: a is not defined

위처럼 간단한 예시를 써보았다.
우선 해당 코드의 함수 내부에선 외부 변수 name 에 접근 가능하며, 당연히 내부에선 a,b 또한 접근할 수 있다.

다만 외부에선 내부에 선언된 a,b를 접근할 수 없었다.
이건 outerEnvironmentReference 덕분에 가능한 일이다.

outerEnvironmentReference 란 현재 호출된 함수가 선언될 당시의 LexicalEnvironment 를 참조한다.
여기서 선언될 당시가 중요한데, car 함수가 선언될 당시의 outerEnvironmentReference글로벌 실행 컨텍스트의 LexicalEnvironment 를 참조하고 있고, 해당 환경의 environmentRecordname 과 같은 변수의 정보들이 기록되어 있다.

그렇기에 car 함수 내부에선 outerEnvironmentReference 를 통해 상위 컨텍스트의 LexicalEnvironment 에 접근하여 environmentRecord 에서 변수인 name 을 사용할 수 있게 된 것이다.

profile
개발 재밌다

0개의 댓글