
인트로
실행 컨텍스트 내용 본 지도 오래됐고 스터디 발표 준비를 하기 위해서 실행 컨텍스트를 다시 한번 펴봅니다
표라던가.. 뭐가 좀 많네요...
실행 컨텍스트를 알면...
실행 컨텍스트를 한 번 알면 자바스크립트가 왜 그렇게 동작하는 이해할 수 있습니다.
식별자 바인딩, 호이스팅이 발생하는 이유, 클로저 동작방식, 비동기 처리 동작 방식... 등
실행 컨텍스트에 대해 알고 나면 실행 컨텍스트를 몰랐을 때는 예측할 수 없었던 동작들을 예측할 수 있게 됩니다.
처음 읽었을 때는 정말 어지러웠지만 알고 나니 매우 유용한 친구였습니다.
소스코드 타입에 따른 실행 컨텍스트 생성
전역 코드 - 전역에 정의된 함수, 클래스 등의 내부 코드는 포함X |
전역 실행 컨텍스트 |
함수 코드 - 함수 내부에 중첩된 함수, 클래스 등의 내부코드 포함X |
함수 실행 컨텍스트 |
eval 코드 | eval 실행 컨텍스트 |
모듈 코드 - 모듈 내부의 함수, 클래스 등의 내부 코드 포함X |
모듈 실행 컨텍스트 |
자바스크립트 엔진에서는 소스코드 평가(선언문) 과정에서 실행 컨텍스트를 생성합니다.
변수 선언, 함수 선언문과 같은 선언문들이 먼저 실행되면서 식별자를 실행 컨텍스트가 관리하는 스코프에 등록합니다.
소스코드 평가가 끝나면 소스코드가 순차적으로 실행됩니다(런타임).
자바스크립트에서 변수 할당과 함수 표현식 평가는 런타임에서 이루어집니다.
소스코드 실행에 필요한 정보는 실행 컨텍스트가 관리하는 스코프에서 취득할 수 있습니다. 소스코드의 실행 결과에 따른 값 변경 역시 실행 컨텍스트가 관리하는 스코프에 다시 등록됩니다.
실행 컨텍스트는 해당 범위 내에서 선언된 변수나 함수의 관리자라고 볼 수 있습니다.
소스코드 타입에 따라 실행 컨텍스트 내용이 살짝 다른데요. 렉시컬 환경에 대한 이야기가 필요하기 때문에 자세한 내용은 아래에서 따로 다뤄보겠습니다.
실행 컨텍스트 스택
전역 코드 평가 후 전역 코드가 실행되다가 함수가 호출되면 전역 코드 실행을 멈춥니다. 호출된 함수 코드 평가 후 함수 코드가 실행됩니다. 그리고 함수 코드 실행이 끝나면 함수 호출 전으로 돌아가야 하는 데요.
코드 실행 순서 관리 역시 실행 컨텍스트의 역할로 실행 컨텍스트 스택을 통해 관리됩니다.
스택은 LIFO(Last In First Out), 마지막으로 추가된 작업이 가장 먼저 삭제된다는 것을 알아두시면 좋습니다.
실행 컨텍스트의 스택도 마찬가지니까요.
위에서 사용한 이 코드로 간단하게 알아보겠습니다.
var Myname = 'I did it'
function printName() {
console.log('last');
return;
}
function findName() {
console.log('first');
let yourName = 'Won'
printName()
console.log('print end');
}
findName();
//first
//last
//print end

1. 전역 코드 평가 + 전역 실행 컨텍스트 생성 + 생성 후 실행 컨텍스트 스택에 push
2. findName 호출 시 전역 코드 실행 중단. findName 내부 함수 코드 평가 및 함수 실행 컨텍스트 생성. 생성 후 실행 컨텍스트 스택에 푸시.
3. findName 함수 평가 및 실행, printName 함수 호출 시 findName 코드 실행 중단. printName 함수 실행 컨텍스트 생성 + 스택에 push, printName 함수가 종료되면 스택에서 pop
4. findName 중단된 곳부터 다시 실행, 함수 종료 후 findName 함수 실행 컨텍스트 스택에서 pop
5. 실행할 코드가 없으므로 전역 실행 컨텍스트 pop
예시를 통해 실행 컨텍스트 스택 최상위에 있는 실행 컨텍스트가 현재 실행 중인 코드의 실행 컨텍스트라는 것도 알 수 있습니다.
또한 실행 컨텍스트는 렉시컬 환경을 가지는데 실행 컨텍스트 스택에서 실행 컨텍스트가 제거되었다고 렉시컬 환경까지 소멸하지는 않습니다. 누군가 참조하고 있다면 해당 렉시컬 환경을 소멸하지 않습니다.
렉시컬 환경
식별자와 스코프는 실행 컨텍스트의 렉시컬 환경에서 관리됩니다.
렉시컬 환경은 어디에서 선언했는가가 중요합니다. 특정 코드가 작성, 선언된 환경에 따라 상위 스코프가 결정됩니다.
var Myname = 'I did it'
function printName() {
return 'woo'
}
function findName() {
let yourName = 'Won'
return printName()
}
위 코드에서 printName, findName, Myname의 렉시컬 환경은 전역입니다.
yourName의 렉시컬 환경은 findName이 되겠죠.
렉시컬 환경은 환경 레코드와 외부 렉시컬 환경에 대한 참조라는 두 개의 컴포넌트로 구성됩니다.
- 환경 레코드 : 스코프 내 식별자 등록 및 식별자의 값 관리하는 저장소. 소스코드 타입에 따라 관리 내용이 달라짐
- 외부 렉시컬 환경에 대한 참조 : 상위 스코프를 가리킴. 이를 통해 스코프 체인 구성
전역 코드
1. 전역 실행 컨텍스트 생성
2. 전역 렉시컬 환경 생성 : 생성 후 전역 실행 컨텍스트에 바인딩
2-1. 전역 환경 레코드 생성
2-1-1. 객체 환경 레코드 생성
2-1-2. 선언적 환경 레코드 생성
.....

객체 환경 레코드
var로 선언한 변수는 전역 객체에 식별자를 키로 등록한 후 암묵적으로 undefined가 할당됩니다. 따라서 변수를 선언하기 전에 참조할 수 있습니다.
함수 선언문이 평가되면 함수 이름과 동일한 식별자가 전역 객체에 키로 등록되고 생성된 함수 객체를 즉시 할당합니다.
선언적 환경 레코드
전역 객체의 프로퍼티가 되지 않습니다. 변수 선언문 도달 전까지 일시적 사각지대에 빠집니다.
console.log(i); //Cannot access 'i' before initialization
let i;
1. 전역 실행 컨텍스트 생성
2. 전역 렉시컬 환경 생성 : 생성 후 전역 실행 컨텍스트에 바인딩
2-1. 전역 환경 레코드 생성
2-1-1. 객체 환경 레코드 생성
2-1-2. 선언적 환경 레코드 생성
2-2. this 바인딩
2-3. 외부 렉시컬 환경에 대한 참조 결정
this 바인딩
전역 환경 레코드의 [[GlobalThisValue]]에 this가 바인딩됩니다. 전역 코드에서는 전역 객체가 바인딩됩니다.
this 바인딩은 전역 환경 레코드와 함수 환경 레코드만 해당됩니다. 객체 환경 레코드와 선언적 환경 레코드에는 this 바인딩이 없습니다.
외부 렉시컬 환경에 대한 참조
전역 렉시컬 환경의 외부 렉시컬 환경에 대한 참조는 null입니다.
외부 렉시컬 환경에 대한 참조까지 끝났다면 전역 코드가 실행됩니다. 순차적으로 변수에 값이 할당되며 함수가 호출되는데 이때 식별자가 필요합니다. 따라서 실행 컨텍스트에서 식별자 결정을 위해 식별자 검색을 합니다.
함수 코드
1. 함수 실행 컨텍스트 생성
2. 함수 렉시컬 환경 생성
2-1. 함수 환경 레코드 생성
2-2. this 바인딩
2-3. 외부 렉시컬 환경에 대한 참조 결정

this 바인딩
함수 환경 레코드의 [[ThisValue]]에 this가 바인딩됩니다. 이때 this는 함수 호출 방식에 따라 결정됩니다.
this 내가 해냄
인트로화살표함수, 생성자함수 그리고 렉시컬 관련 이야기가 나올 때마다 항상 등장하던 this...this에 대해 모르는 상태에서 다른 걸 이해하려고하니 아무것도 못하겠더라구요. 아무것도 못한달
i-did-it.tistory.com
외부 렉시컬 환경에 대한 참조
함수가 평가된 시점에 실행 중인 실행 컨텍스트의 렉시컬 환경의 참조가 할당됩니다.
전역 코드에 정의된 함수의 경우 평가 시점의 실행 컨텍스트가 전역 실행 컨텍스트이기 때문에 전역 렉시컬 환경의 참조가 할당되겠죠. 어디에서 정의됐는가가 중요한 겁니다.
함수의 상위 스코프는 함수 객체의 [[Enviroment]]에 저장됩니다.
외부 렉시컬 환경에 대한 참조까지 끝났다면 함수 코드를 순차적으로 실행합니다.
실행 컨텍스트와 블록 레벨 스코프
모든 블록 코드(함수, if문, 반복문, try/catch 문 등)는 블록 레벨 스코프를 가집니다.
이때 선언적 환경 레코드를 가지는 렉시컬 환경을 새롭게 생성하여 기존 렉시컬 환경과 교체하는데 새롭게 생성된 렉시컬 환경의 외부 렉시컬 환경에 대한 참조는 기존 렉시컬 환경이 됩니다.
이렇게 소스코드 타입별 실행 컨텍스트에 대해 알아보았습니다.
까먹거나 이해가 안 가서 넘어간 부분이 많았는데 정리하면서 두 번 정도 보니 상대적으로 머리에 잘 들어오네요
MDN & 모던 자바스크립트 Deep Dive 내용을 참고하였습니다.
'내가 해냄 > JS' 카테고리의 다른 글
Date 내가 해냄 (0) | 2023.03.31 |
---|---|
jsconfig.json 내가 해냄 (0) | 2023.03.25 |
디스트럭처링 할당 내가 해냄 (4) | 2023.03.21 |
동기/비동기 내가 해냄 (0) | 2023.03.16 |
프로토타입 내가 해냄 (0) | 2023.03.15 |
포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!