Execution Context(이하 EC)는 스코프(식별자 이름과 값의 매칭)와 기본 객체들(intrinsic object - Array, Object 등의 기본 생성자와 그 프로토타입 등)을 가지고 있는 Realm 등 코드 수행 환경에 대한 여러 정보를 가지고 있는 어떤 장치라고 생각하면 된다. 결국 EC는 ECMAScript에서 코드 수행(evaluation) 메커니즘을 표현하기 위한 것이며, 실제 스크립트 엔진들은 이 명세와 완벽히 일치하지 않을 수 있다.
EC란 쉽게 말해 코드들이 실행되기 위한 환경이라고 생각하면 된다.
ECMAScript의 코드 수행을 위한 EC에는 Lexical Environment, Variable Environment 라는 컴포넌트가 존재한다. 간단히 변수의 참조를 기록하는 환경이라고 생각하면 된다.
Lexical 과 Variable은 거의 동일하다. Variable Env도 Lexical Env인데, 두 환경사이 다른 한가지는 다음과 같다.
EC 내부는
code evaluation state
function
Realm
ScriptOrModule
Lexical Env
Variable Env
Generator
등
복잡한 구조를 갖고 있지만,

간단하게 개념을 학습한다는 느낌으로 Lexical Env 내부에 있는
Environment Record
Outer Environment Reference
두 가지만 집중해서 정리하도록 한다.
record를 이해하면 hoisting을 이해할 수 있다.
hositing이란 선언문이 마치 최상단에 끌어 올려진 듯하게 보이는 현상을 말한다
아래 예제 코드를 살펴보면 name이 선언 전 호출되었는데도 에러가 발생하지 않았다.
// 선언 이전에 호출한 경우 에러가 발생하지 않고 undefined를 출력한다
console.log(name) // undefined
var name = 'seob'
console.log(name) // seob
✨ 에러가 발생하지 않은 이유는?
실제로 var 선언문 코드라인을 물리적으로 끌어올렸기 때문이 아니라 자바스크립트 엔진이 전체 코드를 스캔하면서 변수같은 정보를 실행컨텍스트의 record에 기록해두기 때문이다.
자바스크립트 엔진이 전체 코드를 스캔해서 실행컨텍스트를 생성하고 선언문만 실행해서 Environment Record에 기록하는것을 1️⃣ 생성단계라고 한다. 선언문 외 나머지 코드를 순차적으로 실행하면서 Environment Record를 참조하면서 순차적으로 실행하는것을 2️⃣ 실행단계라고 한다.
그리고 생성과정은 어떤 키워드로 선언했는지(변수기준), 어떤 방식으로 선언했는지(함수기준)에 따라 동작이 달라진다.
💡 변수 **키워드 기준**위 내용을 읽고 다시 예제를 살펴보자.
생성 단계에서 var 선언문을 스캔해서 실행컨텍스트에 name을 기록하는데 name은 var 키워드로 선언되었기
때문에 초기화를 거쳐 name : undefined 가 된다.
이후 실행단계에서 console.log 함수로 name을 출력하는데 name값은 초기화된 undefined 를
출력하게 되고 이후 name = 'seob' 코드를 실행하여 실행컨텍스트의 name을 찾아 seob라는 값으로
업데이트 한다.
이후 console.log로 name을 출력하면 업데이트된 seob를 출력하게 된다.
------------------------------------------------------------------------------
console.log(name) // undefined
var name = 'seob'
console.log(name) // seob
var 와 다르게 es6 이후 키워드인 let, const 를 사용하게 되면 var 와 동일하게
실행컨텍스트 환경레코드에 name을 저장하는데, var 와의 차이점은 초기화를 하지 않는다는 것이고
그래서 참조에러가 발생한다.
**이처럼 let, const 로 선언하면 선언 이전에 식별자를 참조할 수 없는데 이를 일시적 사각지대라고 부른다.**
-------------------------------------------------------------------------------
console.log(name) // reference error
const name = 'seob'
console.log(name) // seob
💡 **함수 선언방식 기준**
// 선언 이전에 호출되었지만, var로 선언되었으므로 초기화가 되어 타입에러가 발생
varSleep()
var varSleep = () => {
// do sleep...zzz
}
// 선언 이전에 호출되었고, const로 선언되었기 때문에 참조에러 발생
constSleep()
const constSleep = function(){
// do sleep...zzz
}
// 선언 이전에 호출되었지만, 함수 선언식으로 작성되었으므로 선언과 동시에
// 함수로 초기화가 이뤄졌으므로 정상동작
sleep()
function sleep(){
// do sleep...zzz
}

Outer의 정식 명칭은 Outer Environment Reference (외부 환경 참조)이다. 외부환경은 현재 실행컨텍스트의 바깥 Lexical Environment를 가리킨다. Lexical Environment란 위에서 언급한 Record와 현재 설명하는 Outer를 합친것을 말한다.
// Global
call stack
let lamp = false // off
console.log(lamp)

// Global
let lamp = false
// 2층으로 가는 함수 선언
function goTo2F(){
// 전역 컨텍스트에서 선언한 변수와
// 동일한 이름을 가진 변수 선언
let lamp = true
console.log(lamp)
}
// 함수 실행 => 실행 컨텍스트 생성
goTo2F()

📌 그렇다면 동일한 이름을 가진 변수 lamp를 출력할 때 어떤 변수를 출력하게 될까? 위와 같은 상황에서 변수나 함수의 값을 식별하는 것을 식별자 결정이라고 부른다.
// goTo2F
function goTo2F(){
let lamp = true
function goTo3F(){
const pet = 'puppy'
console.log(pet) // puppy
console.log(lamp) // ???
}
// goTo2F 내에서 goTo3F를 실행시킨다.
goTo3F()
}

✨ goTo3F에서 console.log(pet)을 실행하면 생성단계에서 환경레코드에 기록한 pet의 값인 puppy를 출력한다. 원칙적으로 실행컨텍스트에서 식별자 결정을 하기위해 현재 활성화된 실행컨텍스트를 먼저 확인한다.
그렇다면 위 코드에서 goTo3F내에서 console.log(lamp)를 실행하면 어떤 값을 출력하게 될까?
✨ 추가적으로 goTo2F에서 lamp를 찾았기 때문에 더 이상 1층(Global 실행컨텍스트)으로 내려가 lamp를 찾지 않게 되는데 동일한 식별자로 인해 상위 스코프에서 선언된 식별자의 값이 가려지는 현상을 변수 섀도잉 이라고 부른다!
✨ 또한 3F에서 2F로 식별자를 찾기위해 outer를 타고 이동하는것을 스코프 체인이라고 부른다
실행 컨텍스트는 코드를 실행하는데 필요한 환경을 제공하는 객체이다