코어자바스크립트 - 실행 컨텍스트

김동하·2021년 1월 19일
0

javascript

목록 보기
48/58
post-thumbnail

실행 컨텍스트

실행 컨텍스트란?

  • 실행할 코드에 제공할 환경 정보들을 모아 놓은 객체.
  • 자바스크립트는 어떤 실행 컨텍스트가 활성화되는 시점에 선언된 변수를 위로 끌어올리고(호이스팅), 외부 환경 정보를 구성하고, this 값을 설정한다.
  • 동일한 환경에 있는 코드들을 실행할 때, 필요한 환경 정보들을 모아 컨텍스트를 구성하고 이를 콜 스택에 쌓았다가 가장 위에 있는 컨텍스트와 관련있는 코드들을 실행하는 식으로 전체 코드의 환경과 순서를 보장한다.
  • 우리가 실행 컨텍스트를 구성하는 방법은 함수를 실행하는 것
  • 실행 컨텍스트 객체는 활성화되는 시점에 VariableEnvironment, LexicalEnviornment, ThisBinding 세 가지 정보 수집
  • 실행 컨텍스트를 생성할 때 VariableEnvironment와 LexicalEnviornment가 동일한 내용으로 구성되지만 LexicalEnviornment는 함수 실행 도중에 변경되는 사항이 즉시 반영. VariableEnvironment는 초기 상태 유지.
  • environmentRecord는 매개변수명, 변수의 식별자, 선언한 함수의 함수명 등 수집. 바로 직전의 LexicalEnviornment 정보를 참조하는 outerEnviromentRecord로 구성

렉시컬 환경(Lexical Environment)

  • "현재 컨텍스트의 내부에 a,b,c 식별자들이 있고 외부 정보는 D를 참조하도록 구성돼있다"라는 컨텍스트를 구성하는 환경 정보들을 정의하여 모아놓은 것

호이스팅

  • 호이스팅은 변수 정보를 수집하는 과정에서 더욱 이해하기 쉬운 방법으로 대체한 가상 개념
  • 실행 컨텍스트가 활성화 되면 자바스크립트 엔진은 해당 컨텍스트에 관련된 코드들을 실행하는 데 필요한 환경정보를 수집해서 실행 컨텍스트 객체에 저장한다. 이 객체에 담기는 정보들은 VariableEnvironment(environmentRecord, outerEnviromentRecord), LexicalEnviornment(environmentRecord, outerEnviromentRecord), ThisBinding
  • environmentRecord 에는 현재 컨텍스트와 관련된 코드의 식별자 정보들이 저장된다.

원본 코드

const a = (x) => {

  console.log(x);
  var x;
  console.log(x);
  var x = 2;
  console.log(x);
  
}

a(1)
  • environmentRecord는 현재 실행될 컨텍스트의 대상 코드 내에 어떤 식별자가 있는지 관심. 각 식별자에 어떤 값이 할당될 것인가 관심 없다. 따라서 변수를 호이스팅할 변수명만 끌어올리고 할당 과정은 원래 자리에 남겨둔다. 따라서 변수를 호이스팅 할 때는 변수명만 끌어올린다.

호이스팅 마친 상태

const a = (x) => {

  var x;
  var x;
  var x;
  
  x = 1;
  console.log(x); // 1
  console.log(x); // 1
  x = 2;
  console.log(x); // 2
  
}
a(1)
  • 함수의 경우 함수 선언은 전체를 끌어올린다. 함수 표현식은 변수 선언부만 호이스팅한다.

함수 선언문과 함수 표현식

  • 함수 선언문은 function 정의부만 존재하고 별도의 할당 명령이 없는 것, 반드시 함수명이 정의되어야 함.
  • 함수 표현식은 정의한 function을 별도의 변수에 할당하는 것. 일반적으로 익명 함수 표현식을 말함

함수 선언문

 funtion a () {  // 함수명 a가 곧 변수
   ...
 }
 
 a() 

(익명) 함수 표현식

 const b = function () {  // 변수명 b가 곧 함수명
   ...
 }
 
 b() 

기명 함수 표현식

 const c = function d () {  // 변수명 c, 함수명 d
   ...
 }
 
c() 

스코프

  • 식별자에 대한 유효범위. A의 외부에서 선언한 변수는 A의 외부뿐 아니라 A의 내부에서도 접근이 가능하지만 A의 내부에서 선언한 변수는 오직 A의 내부에서만 접근이 가능하다. 오직 함수에 의해서만 스코프만 형성된다.
  • 식별자의 유효범위를 안에서 바깥으로 차례대로 검색해가는 것을 스코프 체인이라고 한다.
  • 이를 가능케하는 것이 LexicalEnvironment의 두 번째 수집 자료인 outerEnviromentReference

스코프 체인

  • outerEnviromentReference는 현재 호출된 함수가 선언될 당시의 LexicalEnvionment를 참조한다.
  • 선언 시점의 LexicalEnvionment를 계속 찾아 올라가면 마지막엔 전역 컨텍스트의 LexicalEnvionment가 있을 것이다.
  • 또한, outerEnviromentReference는 오직 자신이 선언된 시점의 LexicalEnvionment만 참조하고 있으므로 가장 가까운 요소부터 차례대로만 접근할 수 있도 다른 순서로는 불가능하다.
  • 이러한 구조적 특성 덕분에 여러 스코프에서 동일한 식별자를 선언한 경우에 무조건 스코프 체인 상에서 가장 먼저 발견된 식별자에만 접근 가능하다.

스코프 체인

var a = 1;

var outer = function(){

  var inner = function(){
  
    console.log(a)
    var a = 3;    
    
  }  
  
  inner()
  console.log(a)
  
}

outer();
console.log(a);

스코프 체인 부수기

  1. 시작과 동시에 전역 컨텍스트 활성화. 전역 컨텍스트의 environmentRecord { a, outer } 식별자 저장. 전역 컨텍스트는 선언 시점이 없으므로 전역 컨텍스트의 outerEnviromentReference에는 아무것도 없다.

  2. 전역 스코프에 있는 변수 a에 1을, outer에 함수를 할당

  3. outer 함수 호출. 전역 컨텍스트 코드는 잠시 중단 그리고 outer의 실행 컨텍스트가 활성화 된다.

  4. outer 실행 컨텍스트의 environmentRecord에 { inner } 식별자를 저장한다. outer 함수는 전역 공간에서 선언됐으므로 전역 켄텍스트의 LexicalEnviroment를 참조복사한다. 이를 [GLOBAL, { a, outer} ] 라고 표기. 첫 번째 요소는 실행 컨텍스트, 두 번째 요소는 environmentRecord 객체

  5. outer 스코프에 있는 변수 inner에 함수를 할당

  6. inner 함수를 호출. 이에 따라 outer 실행 컨텍스트는 임시 중단. inner 실행 컨텍스트 활성화

  7. inner 실행 컨텍스트의 environmentRecord에 { a } 식별자 저장. inner 함수는 outer 함수 내부에서 선언됐으므로 outer 함수의 LexicalEnvironment 즉, [outer, { inner }]를 참조 복사한다.

  8. 식별자 a에 접근하고자 함. 현재 활성화 상태인 inner 컨텍스트의 environmentRecord에서 a를 검색. a가 있지만 아직 할당된 값은 없다.

  9. inner 스코프에 있는 변수 a에 3를 할당

  10. inner 함수 실행 졸요. inner 실행 컨텍스트가 콜 스택에서 제거. outer 실행 컨텍스트가 다시 활성화되면서 console.log(a)에 접근. 이때 자바스크립트 엔진은 활성화된 실행 컨텍스트의 LexicalEnvironment에 접근한다. 첫 요소의 environmentRecord에서 a가 있는지 찾고 없으면 outerEnviromentReference에 있는 environmentRecord로 넘아가는 식으로 계속 검색한다. 전역 LexicalEnvironment에 a가 있으니 그 a에 저장된 값 1을 반환한다.
    11.outer 함수 실행이 종료된다. outer 실행 컨텍스트가 콜 스택에서 제거됨. 바로 아래의 전역 컨텍스트가 다시 활성화됨

  11. console.log(a); 식별자 a에 접근. 현재 활성화 상태인 전역 컨텍스트인 environmentRecords에서 a를 검색한다. 바로 a를 찾을 수 있다.

  • 정리 : 전역 컨텍스트 -> outer 컨텍스트 -> inner 컨텍스트 순으로 규모가 작아지는 반면 스코프 체인을 타고 접근 가능한 변수는 늘어난다.
profile
프론트엔드 개발

0개의 댓글