테코톡의 하루님의 '실행컨텍스트' 강의로 보고 요약한 글입니다.
함수가 실행될때마다 함수실행문맥
같은것이 call stack에 쌓인다. 여기서, 함수실행문맥을 실행 컨텍스트
(이하, 실컨) 라고 한다. 실컨에는 크게 아래와 같이 두가지 개념으로 이루어져 있다.
Environment Record (스냅샷, 나의 환경 상태)
: 모든 실행컨텍스트에 포함되어있는 값들. ex> heap안에 있는 객체 주소, 원시타입변수 등등
Outer Environment Reference(바깥 환경에 대한 참조)
: 말그대로 Environment Record에 기록되지 않은 값을 찾을때 outer lexical environment을 참조하는 것을 의미.
그리고 이 두가지를 아울러 lexical environment
라고 한다.
Environment Record + Outer Environment Reference = lexical environment
우선 코드를 한 줄씩 읽어내려가면서 어떤일이 일어나는 지 알아보자. 크게 생성과 실행으로 나뉜다.
아래와 같은 코드가 있다고 했을때 어떤식으로 컴퓨터가 코드를 읽어나가는지 살펴보자.
console.log(TvChannel) // undefined ==> 선언 및 생성
var TvChannel = 'Netflix'
생성단계 => TvChannel을 환경레코드에 undefined
로 초기화 시켜둠.
실행단계 => console.log에서 환경레코드에 기록된 값을 참조하여 출력
let, const같은경우 선언이전에 식별자를 참조할 수 없게됨. 평가과정에서 var와 다르게 undefined로 init하지 않기 때문 ==> TDZ.
일반적인 다른 언어처럼 초기화 전에는 변수 참조 할 수 없다는 일반적 프로그래밍 방식, 언어자체가 보완됨
var같은경우 평과과정에서 global에 undefined로 init됨
- 선언 ==> 초기화(식별자에 암묵적으로 undefined 값 바인딩)
<함수 같은 경우>
함수 표현식으로 선언하면 환경레코드에 기록된 값이 없거나 undefined이다.
함수 선언문으로 선언하면 선언과 동시에 함수가 환경레코드에 기록됨. 그래서 코드 이전에 불러와도 잘 작동함.
console.log(study0()) // TypeError: study2 is not a function
console.log(study1()) // reference error: study is not defined
console.log(study2) // f study2{}
var study0 = () => {} // 함수 표현식
const study1 = () => {} // 함수 표현식
function study2() {} // 함수 선언문
그럼 자바스크립트가 바깥 환경을 어떻게 참조하는지 알아보자.
let lamp = false;
function goTo2F() {
let lamp = true;
console.log(lamp)
function goTo3F() {
let pet = 'puppy'
console.log(pet) // 'puppy'
console.log(corona) // corona is not defined
console.log(lamp) // true
}
goTo3F()
}
goTo2F()
여기서 lamp가 두개 있기 때문에 로그에 출력해야할지 자바스크립트는 결정해야한다. 이 결정을 식별자 결정(Identification Resolution)
이라고 한다.
우선 goTo3F
를 살펴보자.
pet
변수를 출력하는 코드를 살펴보자. 자신의 환경기록에 있으므로 바로 출력하면 끝!
lamp라는 변수를 출력하는 코드를 살펴보자.
여기서 자바스크립트는 goTo2F
안에 있는 environment record
안에서 변수를 찾을 수 있게 된다. 그러므로 더 이상 바깥으로 나가지 않는다. 여기서 바깥
이란 lexical environment
을 의미한다.
corona
는 어떻게 될까?
요 경우는, 아무리 전역 lexical environment까지 참조했는데도 없기 때문에 에러가 나는 것이다.
여기서 식별자들을 결정할때 타고타고 올라가는 행위를 스코프 체인닝
이라고 한다.
그럼 실행컨텍스트를 한 문장으로 정리한다면??
코드를 실행하는데 필요한 환경을 제공하는 객체
선언될 당시의 주변 환경을 기억하고 그것을 스냅샷으로 찍어 실행컨텍스트 객체안에 보관하는 것이라고 봐도 될 것 같다. 그리고 이 컨텍스트를 통해 식별자를 효율적으로 인지 가능해졌다.
여기서 잠깐 비슷한 단어로 헷갈릴 수 있는 lexical scope에 관해서 알아보려고 한다.
우선 코드부터 보자
const v = "전역 변수";
function b() {
console.log(v); // "전역 변수"
}
function a() {
const v = "지역 변수";
b();
}
a();
여기서 나는 b 함수에 있는 콘솔로그가 "지역변수"
를 출력할 줄 알았으나 "전역변수"
를 출력하였다.
그 이유는 자바스크립트에서는 함수를 호출한 시점이 아니라 선언한 시점
에서의 스코프를 environment record
에 기록하니 그런것 같다. 선언한 시점에서의 스코프에 따라 상위스코프가 결정되는 것을 lexical scope
또는 Static scope
라고도 한다.