실행 컨텍스트

유섭·2022년 7월 15일

자바스크립트

목록 보기
3/3

실행 컨텍스트

Execution Context(이하 EC)는 스코프(식별자 이름과 값의 매칭)와 기본 객체들(intrinsic object - Array, Object 등의 기본 생성자와 그 프로토타입 등)을 가지고 있는 Realm 등 코드 수행 환경에 대한 여러 정보를 가지고 있는 어떤 장치라고 생각하면 된다. 결국 EC는 ECMAScript에서 코드 수행(evaluation) 메커니즘을 표현하기 위한 것이며, 실제 스크립트 엔진들은 이 명세와 완벽히 일치하지 않을 수 있다.

EC란 쉽게 말해 코드들이 실행되기 위한 환경이라고 생각하면 된다.

ECMAScript의 코드 수행을 위한 EC에는 Lexical Environment, Variable Environment 라는 컴포넌트가 존재한다. 간단히 변수의 참조를 기록하는 환경이라고 생각하면 된다.

Lexical 과 Variable은 거의 동일하다. Variable Env도 Lexical Env인데, 두 환경사이 다른 한가지는 다음과 같다.

  • Lexical - let, const 변수 바인딩과 함수 선언을 저장하는데 사용
  • Variable - var 변수 바인딩을 저장하는데만 사용

EC 내부는

code evaluation state

function

Realm

ScriptOrModule

Lexical Env

Variable Env

Generator

복잡한 구조를 갖고 있지만,

간단하게 개념을 학습한다는 느낌으로 Lexical Env 내부에 있는

Environment Record

Outer Environment Reference

두 가지만 집중해서 정리하도록 한다.

Record


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 는 생성단계에서 값을 초기화하는데 암묵적으로 undefined로 초기화 한다.
  • let, const 는 생성단계에서 값을 초기화 하지 않는다.

위 내용을 읽고 다시 예제를 살펴보자.


생성 단계에서 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의 정식 명칭은 Outer Environment Reference (외부 환경 참조)이다. 외부환경은 현재 실행컨텍스트의 바깥 Lexical Environment를 가리킨다. Lexical Environment란 위에서 언급한 Record와 현재 설명하는 Outer를 합친것을 말한다.

  1. 전역 실행컨텍스트에서 lamp를 기록한다.
// Global
																					call stack
let lamp = false // off

console.log(lamp) 

  1. 전역 실행 컨텍스트에서 goTo2F라는 함수를 선언하고 실행시킨다. 그럼 콜 스택에는 goTo2F에 대한 실행 컨텍스트를 생성하고 매개변수와 선언한 변수에 대해 기록한다.
// Global

let lamp = false

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

📌 그렇다면 동일한 이름을 가진 변수 lamp를 출력할 때 어떤 변수를 출력하게 될까? 위와 같은 상황에서 변수나 함수의 값을 식별하는 것을 식별자 결정이라고 부른다.

  1. goTo2F 함수에서 goTo3F 함수를 선언하고 실행시킨다. 그리고 goTo3F 함수에서 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)를 실행하면 어떤 값을 출력하게 될까?

  • 정답은? true값을 갖고있는 lamp를 출력하게 되는데, 식별자 결정단계에서 현재 실행컨텍스트 내부를 탐색하고 내부에 해당값이 존재하지 않는 경우 현재 실행컨텍스트의 바깥 렉시컬 환경을 살펴보게 된다. goTo3F의 바깥 렉시컬 환경은 goTo2F이므로 goTo2F에서 선언된 lamp를 확인하면 해당 값을 출력하는 것이다!

✨ 추가적으로 goTo2F에서 lamp를 찾았기 때문에 더 이상 1층(Global 실행컨텍스트)으로 내려가 lamp를 찾지 않게 되는데 동일한 식별자로 인해 상위 스코프에서 선언된 식별자의 값이 가려지는 현상을 변수 섀도잉 이라고 부른다!

✨ 또한 3F에서 2F로 식별자를 찾기위해 outer를 타고 이동하는것을 스코프 체인이라고 부른다

결론적으로 실행컨텍스트란?


실행 컨텍스트는 코드를 실행하는데 필요한 환경을 제공하는 객체이다

참고자료


자바스크립트 함수 (1) - 함수 객체, 함수 객체 생성 : NHN Cloud Meetup

https://www.youtube.com/watch?v=EWfujNzSUmw

0개의 댓글