실행 컨텍스트

onezerokang·2022년 1월 10일
0

Javascript

목록 보기
7/7
post-thumbnail

오늘은 자바스크립트의 실행순서나, 동작원리를 이해하려면 꼭 알아야 할 실행 컨텍스트를 공부하고 정리해보려고 합니다.

해당 내용은 주로 책, 코어자바스크립트에서 공부한 내용과 필자가 추가로 공부한 내용을 정리한 글입니다. 또 자바스크립트의 call stack, queue, event loop에 대핸 따로 설명하지 않으므로 이 부분에 궁금하신 분들은 https://www.youtube.com/watch?v=8aGhZQkoFbQ 강의를 시청하시길 바랍니다(한글자막있음)

실행컨텍스트의 정의

실행컨텍스트는 영어로는 execution context이며 전역함수, eval, 함수, module이 실행될 때 생성되는, 해당 코드 실행에 필요한 환경정보를 담은 객체를 의미합니다. 전역함수은 따로 신경쓸 필요가 없고, eval은 사용할 필요가 없기때문에 일반적으로는 함수가 호출될 때 실행컨텍스트가 생성되어 call stack에 쌓인다라고 알고 계시면 될 것 같습니다.

실행컨텍스트는 어떻게 구성되어 있을까?

앞서 실행컨텍스트는 함수 실행에 필요한 환경정보를 저장한 객체라고 이야기 했습니다. 그렇다면 실행 컨텍스트에는 어떤 정보들이 담겨 있을까요?

  1. VariableEnvironment
  2. LexicalEnvironment
  3. ThisBinding

VariableEnvironment

처음 함수가 호출될 때 함수내의 식별자, 함수선언, 매개변수등을 수집하여 VariableEnvironment에 저장합니다. 그리고 이를 복사하여 LexicalEvironment를 생성하는데, VariableEnvironment 같은 경우 처음 정보를 계속 유지하지만(snapshot) LexicalEnvironment는 데이터가 변경될 때 해당 데이터를 반영합니다.

LexicalEnvironment

LexicalEnvironment의 구조자체는 VariableEnvironment와 같습니다. LexicalEnvironment는 현재 실행환경의 정보를 저장한 EnvironmentRecord와 이전 컨텍스트의 LexicalEnvironment의 정보를 가지고 있는 outer environment record로 구성되어 있습니다.

호이스팅과 environment record

자바스크립트는 코드를 실행하기전에 해당 컨텍스트에 있는 함수선언문, 식별자, 매개변수들을 environment record에 저장합니다. 그래서 자바스크립트는 코드 실행 전, 현재 컨텍스트에 어떤 식별자가 있는지 알수 있고, 선언하기전에 해당 식별자에 접근할 수 있습니다(다만 아직 값이 할당된 상태는 아니기에 undefined가 출력됩니다)

function a(){
  console.log(b) //undefined
  var b = 'bbb'
  console.log(b) // 'bbb'
  
}
a()

사실 식별자를 맨 위로 끌어올린다는 호이스팅이라는 개념은 코드 실행전 environment record에서 식별자와 함수를 수집하는 것을 이해하기 쉽게 생긴 개념입니다.

함수선언문 vs 함수 표현식

함수선언문은 function a {}같은 방식으로 함수를 선언하는 것이고 함수 표현식은 var a = function () {}과 같이 함수를 만들어 식별자에 할당하는 것을 의미합니다.


a() //"hello"
function a () {
  console.log("hello");
}

b()// b is not a function
var b = function () {
  console.log("world!");
}
b()//"world!"

함수 선언문 같은 경우 environment record에서 식별자를 수집할 때 함수 전체를 수집하지만 함수 표현식은 해당 함수의 식별자만 수집합니다. 따라서 함수 선언문을 사용할 경우 함수가 선언되기 전에 호출해도 문제 없이 호출됩니다.

다만 이런 방식은 혼란을 야기할 수 있어 함수 선언문은 사용하지 않는 것이 좋습니다. 실수로라도 함수이름이 겹쳤을 때 호이스팅되면 마지막에 선언된 함수가 이름이 같은 모든 함수를 덮어씌우기 때문입니다.


a() // hi
function a () {
  console.log("AAA");
}

a() // hi

// 1000line code

function a () {
  console.log("hi");
}
a() //hi

사실 실무에서는 주로 화살표 함수를 쓰기 때문에 큰 의미는 없지만 기본적인 개념을 알아는 둬야 이런 방식으로 코딩할 일이 없을 것입니다.

const, let과 호이스팅

앞서말한 environment record가 코드 실행전 현재 컨텍스트의 식별자를 수집하는 과정을 쉽게 이해하기 위해 호이스팅이라는 개념을 사용한다고 했습니다. 그런데 const와 let은 코드상에서 선언하기전에 접근하면 에러를 발생시킵니다. 그러면 이들은 environment가 식별자를 수집할 때 어떻게 동작할까요?

console.log(name) //undefnied
var name = "minsu";
console.log(name) //minsu

console.log(name2) // name2 is not defined
const name2 = "youngji";
console.log(name3); 

바로 environment record에 수집은 되지만 아직 메모리에 저장하진 않은 상태가 됩니다. var는 environemnt rocord에 수집과 메모리에 저장을 동시에 하여 접근이 가능하지만 let과 const는 수집은 되었지만 아직 메모리에 저장되지 않았기 때문에 에러가 발생하는 것입니다.

이렇게 const let 식별자가 아직 메모리에 저장되지 않은 시기를 TDZ(Temporal Dead Zone)이라고 부릅니다.

식별자 수집, 데이터 할당 되는 과정

  1. environment record에 const, let, class, function 등이 수집된다.
  2. 해당 식별자에 대한 정보를 메모리에 저장한다.
  3. 값(데이터를 할당한다).

var는 1번과 2번이 동시에 진행되어 선언문 전에 접근이 가능하지만 let과 const는 선언문을 실행할 때 2번이 실행되기에 선언전에는 접근할 수 없다.

스코프 체인과 outer environment reference

스코프는 정보의 유효범위를 이야기 합니다. 스코프 체인은 컨텍스트에서 식별자나 함수에 접근할 대 현재 컨텍스트에서 먼저 탐색하고 없을 시 outer environment reference를 통해 이전 컨택스트에서 탐색하는 것을 의미합니다. 이때문에 외부 컨텍스트에서는 내부 컨텍스트에 식별자에 접근할 수 없으며, 내부 컨텍스트에 해당 식별자가 있을 때는 외부 컨텍스트에 접근할 수 없습니다

스코프와 contst let

자바스크립트에서 var는 함수스코프를 띄지만, ES6에서 도입된 constlet은 블록 스코프를 띕니다.

profile
블로그 이전 했습니다: https://techpedia.tistory.com

0개의 댓글