[JavaScript] 실행 컨텍스트 (Execution Context) - 2

minbr0ther·2022년 3월 21일
0

javascript

목록 보기
3/9
post-thumbnail

[JavaScript] 실행 컨텍스트 (Execution Context) - 1 보러가기

[10분 테코톡] 💙 하루의 실행 컨텍스트(15분) 를 보고 정리한 글입니다 :)

🪐 Outer로 JS 스코프체이닝 이해하기

Outer의 정식 명칭은 외부 환경 참조(Outer Environment Reference: 바깥 Lexical Environment를 카리킴) 실행 컨텍스트 내부에 렉시컬 환경(또는 정적 환경)이 있고, 렉시컬 환경 내부에는 Record와 Outer가 있습니다.

let lamp = false;

// 1. 함수선언문 방식이라 선언하는 동시에 환경레코드에 생성된 함수가 통째로 기록됩니다.
function goTo2F() { 
  
  // 3. 매개변수가 있다면 그것도 환경레코드에 기록하겠지만 없으니 넘어가서 lamp를 기록합니다. 
  let lamp = true; 
  
  // 4. lamp의 값을 출력하려고 환경레코드를 보니, 불이 꺼진 램프(false)와 켜진 램프(true)가 두개 있습니다.
  console.log(lamp);
}

// 2. 함수를 실행했을때 새로운 샐행컨텍스트를 생성합니다.
goTo2F(); 
  1. 이런 상황에서 변수나 함수의 값을 결정해내는 것을 식별자 결정(Identifier Resolution: 코드에서 변수나 함수의 값을 결정하는 것) 이라고 합니다.

1장에서도 자바스크립트 엔진이 어떤 식별자의 값을 결정하는 일을 반복하고 있다고 느끼셨을 것입니다. '식별자 결정'은 2장에서 제일 중요한 키워드 입니다 ⭐️ 콜 스택 안에 동일한 식별자가 여럿일 때, 자바스크립트 엔진이 어떻게 outer를 활용해서 의사결정을 하는지 알아보겠습니다.


다시 되돌아 가자면 2. goTo2F(); 함수를 실행했을때 함수의 실행 컨텍스트를 새로 생성합니다. 이때 자바스크립트 엔진은 새로 생성된 실행 컨텍스트에 바깥 렉시컬 환경으로 돌아갈 수 있는 outer(사다리)를 남겨놓습니다.

outer(사다리)를 사용하면 필요한 경우에 이전 실행 컨텍스트의 환경레코드에 저장된 식별자도 참조할 수 있게 되었습니다 😮


// Function goTo2F
let lamp = true;

function goTo3F() {
  ...
};
  
goTo3F();

이어서 goTo2F 함수가 실행됩니다. lamp를 True로 기록하고 위의 예시와 다르게 goTo2F내부에서 goTo3F 함수도 새롭게 선언해보겠습니다. 그러면 goTo3F 함수가 기록되고 goTo2F 함수 안에서 다시 goTo 3F 함수가 호출됩니다.

함수가 호출되었으니 그럼 또 새로운 실행컨텍스트가 생성되고, 이전 렉시컬 환경(goTo2F)을 가리키는 outer(사다리)를 현재의 실행컨텍스트에 저장합니다.

이제 goTo3F함수를 실행합니다. 3층에서는 pet에 puppy를 할당합니다. 그리고 pet의 값을 출력하려고 하면, 자바스크립트 엔진은 pet의 값을 결정하기 위해 환경레코드를 봅니다.

콜스택을 통틀어서 pet이 하나밖에 없긴하지만 원칙적으로 현재 활성화된 실행컨텍스트의 환경레코드를 먼저 봅니다. pet의 값이 puppy니까 자바스크립트 엔진은 puppy를 잘 출력해냅니다.

만약 뜬금없이 goTo3F함수 안에서 console.log(corona);를 하려고 하면 어떻게 될까요? 현재 활성화된 실행컨텍스트의 환경레코드를 보아도, corona는 없습니다. 그럼, 자바스크립트 엔진은 outer가 가리키는 바깥 렉시컬 환경(goTo2F)으로 가서 corona를 찾기 시작합니다. 역시 2F에도 corona는 없습니다.

그럼 또 outer를 타고 바깥 렉시컬 환경(전역 실행 컨텍스트, 1F)로 갑니다. 역시 corona는 찾아볼 수 없습니다. 전역 실행 컨텍스트는 더 바깥이랄게 없는 최상위 실행 컨텍스트이기 때문에 자바스크립트 엔진은 corona를 찾는 것을 멈추고, 없다는 결론을 내립니다. 그리고 없는 식별자를 참조하려고 했기 때문에 Reference Error를 내뿜게됩니다.

마지막으로 출력하려고 했던 lamp를 어떻게 출력할 수 있을지 알아보겠습니다. 현재 활성화된 실행컨텍스트(3F)에는 lamp가 없어서 outer(사다리)가 가리키는 바깥 렉시컬 환경(2F)로 가서 다시 lamp를 찾게됩니다. 그리고 켜져있는 lamp를 찾아서, 값을 on으로 출력해냅니다.

여기서 주목할점은 2층에서 이미 lamp를 찾았기 때문에 더 이상 1층으로 내려가서 찾아보지 않는다는 점입니다. 2층의 lamp와 1층의 lamp가 같은 이름이기 때문에 즉, 식별자가 같기 때문에 1층의 lamp가 켜져있는지 꺼저있는지는 2층에서도 3층에서도 절대 알 수가 없습니다.

이렇게 동일 식별자로 인해 상위 스코프에서 선언된 식별자의 값이 가려지는 현상을 변수 섀도잉(Variable Shadowing: 동일한 식별자로 인해 상위 스코프에서 선언된 식별자의 값이 가려지는 현상) 이라고 합니다.

이렇게 콜 스택에 층층이 실행 컨텍스트가 쌓여있을때 어떻게 식별자를 결정하는지 알아봤습니다. 현재 활성화된 실행 컨텍스트는 오직 하나이지만, 이전 렉시컬 환경을 가리키는 'outer(사다리)'로 타고타고 갈 수 있기 때문에 3층에 없으면 2층으로 가서 찾고, 2층에 없으면 1층으로 가서 찾을 수 있었습니다.

이렇게 식별자를 결정할 때 활용하는 스코프들의 연결리스트를 스코프 체인(Scope Chain: 식별자를 결정할 때 활용하는 스코프들의 연결리스트) 라고 하고, 식별자를 결정하기 위해 타고 타고 가서 찾는 과정 자체를 스코프체이닝(Scope Chaining) 이라고 합니다.


🌼 Execution Context 정리

실행 컨텍스트를 한마디로 다시 정의하자면 아래와 같습니다.

"코드를 실행하는데 필요한 환경을 제공하는 객체"

여기서 환경(Environment)는 코드 실행에 영향을 주는 조건이나 상태를 의미합니다. 따라서 코드를 실행하는데 필요한 조건이나 상태를 모아둔 객체가 바로 실행 컨텍스트 입니다. 이전과는 다르게 ES6에 들어서는 실행 컨텍스트라는 하나의 덩어리, 하나의 묶음으로 관리하게 되었습니다.

  1. 스코프가 호출되는 위치와 상관없이 어디에 선언되어있느냐에 따라 정적으로 결정됩니다.

  2. 하나의 컨텍스트 개념으로 묶어놨기 때문에 자바스크립트 엔진은 더욱 빠르고 효율적으로 식별자를 결정할 수 있게 되었습니다.

"식별자 결정을 더욱 효율적으로 하기 위한 수단"

실행 컨텍스트는 코드를 실행할때 식별자를 더욱 효율적으로 결정하기위한 수단으로써 필요한 정보를 한데 모아 제공하는 객체라고 정리할 수 있습니다.

1장에서는 자바스크립트 엔진이 코드를 실행할 때 생성단계에서 선언문만 먼저 환경레코드에 기록한다는 것 그리고 변수 호이스팅과 함수 호이스팅을 각각 알아봤습니다.

2장에서는 아우터의 동작을 통해 스코프 체이닝이 어떻게 구현되는 것인지 알아봤습니다. 마지막으로 실행 컨텍스트를 "코드를 실행하는데 필요한 환경을 제공하는 객체"로 정리했고 보다 효율적인 식별자 결정을 위해 필요하다는 것도 알게 되었습니다.


🌐 참조 링크

profile
느리지만 꾸준하게 💪🏻

0개의 댓글