<자바스크립트> 실행 컨텍스트 -1

Woongbee Park·2022년 8월 19일
0

오늘은 실행 컨텍스트에 관해서 정리해보려고 한다.
역시나 <코어 자바스크립트> -정재남 (위키북스 출판)
이 책에서 본 내용을 요약한 글이다.
이 책 정말 추천!

실행 컨텍스트는 "실행할 코드에 필요한 정보들을 모아 놓은 객체" 다.


어떤 코드를 실행할 때 필요한 정보란? 코드 안에 어떤 변수가 있는지, 외부에 선언된 변수나 함수를 쓰지는 않는지와 같은 정보들이다. 말 그대로 코드를 실행할 때 필요한 정보들을 모아놓은 객체이다. 실행 컨텍스트는 함수가 실행되면서 생성되고, STACK에 차곡차곡 쌓여서 하나씩 실행된다. 즉, 함수를 실행다는 것은 함수의 실행 컨텍스트를 구성한다는 것과 같은 뜻이다.

실행컨텍스트를 생성하는 방법은 크게

1. 전역공간
2. 함수

2가지 인데, 전역 공간 실행 컨텍스트는 자바스크립트 파일이 실행되면서 자동으로 생성되므로, 우리가 실행 컨텍스트를 구성하는 방법은 함수를 실행하는 것 뿐이다.

실행컨텍스트는 3가지 정보로 구성되어 있다.

1. VariableEnviroment
2. LexicalEnviroment
3. ThisBiding

이게 말이 어려워서 읽을 때 진입장벽이 좀 있다.
일단 단어 자체도 어려운데, 단어 뜻을 알아도 단어를 읽고 직관적으로 추정되는 뜻과 실제로 저 단어가 자바스크립트에서 의미하는게 달라서,(사실 직관적 추론도 잘 안되는 단어였다) 더 어렵다. 내용보다 단어 때문에 더 어려운 느낌이랄까?

단어를 이해하겠다는 마음을 버리고 내용에만 집중해서 이해한 뒤, 이해한 내용에 단어를 갖다 붙여 외우니 더 편했다.


내용 자체는 간단하다.
위에서 말했듯, 코드 안에 어떤 변수와 함수가 있는지, 함수 외부에는 어떤 정보들이 있고 코드 내에서 함수 외부의 정보를 쓰는지 와 같은 지극히 상식적인, 말 그대로 코드를 실행하기 위해 필요한 내용들이 어려운 단어로 설명되어있을 뿐이다.


2.LexicalEnviroment

얘 먼저 설명하겠다. 얘가 제일 중요하기 때문이다.
LexicalEnviroment 안에서는 2가지 내용으로 나누어 저장하는데,


(1) enviromentRecord
(2) outerEnviromentReference

이렇게 2가지 이다. 얘네들은 단어를 곱씹으면 뜻을 알 수 있고, 그 뜻이 맞다.

(1)enviromentRecord : 코드 내에서 선언된 함수와 식별자 정보를 저장한다.
(2)outerEnviromentReference: 함수가 선언된 외부 객체의  
                 LexicalEnviroment 참조값을 저장한다. 

함수를 실행하면, 실행 컨텍스트가 생성되기 시작하고, 실행 컨텍스트 내의 LexicalEnviroment 는 함수 안에 선언된 함수들과 식별자 정보들을 수집해서 enviromentRecord에 저장한다. 여기서 핵심은 식별자 정보만 수집하고, 식별자에 할당된 데이터는 수집하지 않는다는 것이다.

function ABC(){

let a= 10;    //변수 선언

let b = function(a){     //함수 표현식
console.log(a)
  };
  
function c(a){    //함수 선언문
console.log(a)
 };
  
}

만약 위 코드를 실행하면,
ABC의 실행 컨텍스트가 구성되기 시작한다.
ABC 실행 컨텍스트의 LexicalEnviroment는
함수 내에 선언된 식별자 a,b 와 함수 function c()를 enviromentRecord 에 저장한다.


이 부분만 봐도, 호이스팅이 뭐였는지 함수 선언문과 함수 표현식의 차이가 왜 발생하는지를 알 수 있다.
흔히 변수를 끌어올린다 라고 알고있는 호이스팅은, 함수가 실행되면서 함수의 실행 컨텍스트가 자신의 내부에 선언된 식별자 정보들을 모아 한군데에 저장하는 이 과정을 말하는 것이다.

그래서 자바스크립트 파일이 실행되면, 자동으로 구성되는 전역 객체의 실행 컨텍스트가 전역 공간에 선언된 식별자 정보들을
LexicalEnviroment > enviromentRecord 여기에 다 저장해놓기 때문에,

변수 선언 이전에 변수를 참조해도 ReferenceError가 아닌 undefined가 출력되는 것이다. undefined가 출력되는 이유는, 실행 컨텍스트가 "식별자 정보만" 저장하고 그 내용은 미리 저장하지 않기 때문이다. 그래서 변수가 선언되었다는 건 알겠으나, 그 내용은 아직 모르겠다(undefined)가 출력되는 것이다.



실행 컨텍스트는 변수에 데이터를 할당하는 경우에는 식별자 정보만 저장하지만, 변수 선언 키워드(let,var,const) 없이 정의된

함수 선언문은 함수를 그 내용까지 통째로 미리 저장해둔다.
그래서 함수 선언문으로 선언된 함수는 함수 선언 이전에 사용해도 결과값을 정상적으로 출력한다!

function ABC(){

let a= 10;    //변수 선언

let b = function(a){     //함수 표현식
console.log(a)
  };
  
function c(a){    //함수 선언문
console.log(a)
 };
  
}

위 코드에서 b에 할당된 함수를 함수 선언 이전에 사용하려고 하면 undefined가 출력되는 반면, function c()는 함수 선언 이전에 사용해도 결과값을 정상적으로 출력한다. 그 이유는?
실행 컨텍스트가 변수는 식별자 정보만 미리 저장하고, 함수는 통째로 저장해두기 때문이다. 함수 선언문과 함수 표현식의 가장 큰 차이이다.

▲노란색으로 하이라이트 된 부분이 LexicalEnviroment > enviromentRecord가 저장하고 있는 내용들이다.

이런 차이 때문에 함수 선언문과 함수 표현식의 차이를 잘 알고 있어야 한다. 만약 여러 사람이 같은 파일에 작업을 하는 경우, 내가 ABC 라는 함수를 함수 표현식으로 선언했는데, 5000줄 쯤 뒤에 다른 사람이 같은 이름의 함수를 함수 선언문으로 선언한다면? 실행 컨텍스트가 내가 선언한 함수의 식별자 "ABC"를 저장한 뒤, 함수 선언문 function ABC()를 만나면 이 함수를 통째로 저장하고 식별자 "ABC"위에 덮어 쓸 것이기 때문에 내가 선언한 함수는 사용할 수 없게 된다. 그리고 이유를 찾으려고 저 코드 속을 헤매게 되겠지....



LexicalEnviroment > (2) outerEnviromentReference

이곳에는 함수 바깥에 있는 함수의 LexicalEnviroment 참조값을 저장한다. 거기에는 바깥 환경에 저장된 변수의 식별자 정보와 함수 정보들이 들어있을거다. 그렇기 때문에 함수 내부가 아닌 바깥에 선언된 변수 a를 쓴다고 하면, outerEnviromentReference 가 참조하고 있는 바깥 환경 정보를 따라 쭉쭉 올라가서 일치하는 변수를 찾은 뒤 그 값을 가져다가 쓴다.

외부함수 내부에 선언된 내부함수는 외부함수에 선언된 변수를 쓸 수 있다.

여기서 스코프 체인이 뭔지, 클로저가 뭔지까지도 알 수 있다.
하지만 오늘은 너무 힘드니까 여기까지 쓰겠다...

profile
나는야 개발자

0개의 댓글