Execution Context [2] - Lexical Env

Marullo·2021년 3월 22일
1
post-thumbnail

JS 엔진은 함수를 실행하기 위해, 함수 실행에 필요한 모든 변수나 함수등을 실행 컨텍스트라는 덩어리에 묶는다. 이번 포스트에서 실제 그 덩어리는 어떻게 생겼는지를 알아보겠습니다.


실행 컨텍스트 내부 구조

  • JS 엔진은 함수를 실행해야 할 때, 위와 같은 빈 껍데기의 실행 컨텍스트를 만들어 Call Stack에 Push한다. 이후 Call Stack 최상단에 위치한 컨텍스트로 컨트롤을 옮긴 후에 실행 컨텍스트의 내용을 초기화한다.
  • 실행 컨텍스트에는 상태(환경)을 저장하기 위한 3개의 컴포넌트가 존재한다.
    1. Lexical Environment
    2. Variable Environment
    3. This Binding
실행컨텍스트_EC : {
    렉시컬환경컴포넌트_LEC : { },
    변수환경컴포넌트_VEC : { },
    This바인딩컴포넌트_TBC : { }
}

이제 3개의 컴포넌트에 대해 차례차례 알아보자



1. LEC (Lexical Environment Component)

LEC의 내부 구조는 다음과 같다.

렉시컬 환경 컴포넌트 : {
    환경 레코드 : {
    	선언적 환경 레코드 : { },
        오브젝트 환경 레코드 : { },
    },
    외부 렉시컬 환경 참조 : {}
}
  • 함수 내외부에 존재하는 "함수나 변수" 관련한 환경을 설정하는 공간이다. 여기서 주로 Identifier Resolution(식별자 해결)이 일어난다.
  • 실행 컨텍스트 초기화 단계에서 해석딘 함수와 변수가 Key-Value 형태로 저장된다.
    - 변수는 변수명 : undefined 형태로 저장되며, 함수선언문함수명 : undefined 형태로 저장된다. 초기화 단계가 끝나고 코드가 실행되면서 Value 값들이 적용된다.


1.1 외부 렉시컬 환경 참조

  • JS 엔진은 함수 바로 바깥에 있는 변수도 참조할 수 있도록 설정을 한다. 즉 실행 컨텍스트 생성을 유발하는 function 키워드가 속한 Scope의 변수나 함수들을 외부 렉시컬 환경 참조에 저장한다.
  • 외부 렉시컬 환경 참조를 위해 엔진이 어떤 처리를 하게 되는데, 이것은 다음 포스트에서 엔진이 function 키워드를 만났을 때, Function Object가 처리되는 방식을 보면 된다.


1.2 환경 레코드

환경 레코드는 선언적 환경 레코드오브젝트 환경 레코드로 나뉜다. 모든 실행 컨텍스트는 이와 같은 동일한 구조를 갖지만, 동적 환경은 오브젝트 환경 레코드를 사용하고 정적 환경은 선언적 환경 레코드를 사용한다.

1.2.1 선언적 환경 레코드

function, 일반 변수, catch문 내부 변수들은 선언적 환경 레코드에 저장된다. 여기에 저장되는 환경들은 정적으로 설정된다. 즉 한 번 설정되면, 값은 변할지라도 key값은 변하지 않는다.


1.2.2 오브젝트 환경 레코드

실행컨텍스트 : {
    글로벌환경 : {
        환경레코드 : { 오브젝트환경레코드 : 글로벌 오브젝트 },
        외부렉시컬환경참조 : null
    }
}

JS 엔진은 global object의 생성과 with을 만나면 동적 환경(즉, 환경이 런타임때마다 변하는)을 생성한다. 오브젝트 환경 레코드는 동적으로 처리되는 환경이 저장되므로, 오브젝트 환경 레코드만 사용하면 된다. 글로벌 오브젝트는 어디에도 속하지 않으므로 외부 렉시컬 환경 참조값은 NULL이다.


1.3 Example

var value = 100
function getMyValue(){
  	var value = 200
    var temp = 300
    return value
}
getMyValue()
getMyValue 실행 컨텍스트 : {
    렉시컬 환경 컴포넌트 : {
        환경레코드 : { 
            선언적 환경 레코드 : {
          	value : 200,
                temp : 300
            },
           오브젝트 환경 레코드 : { }
        },
        외부렉시컬환경참조 : {
            value : 100
        }
    }
}
  1. 엔진은 getTotal 함수의 function 키워드를 해석하면서 Function Object를 생성하고 Function Object를 초기화한 후, 현재 컨텍스트(글로벌 컨텍스트)의 오브젝트 환경 레코드에 getMyValue : Function Object형태로 저장한다.
    • 글로벌 컨텍스트는 동적환경이므로 오브젝트 환경 레코드에 환경을 설정한다.
  2. getMyValue 함수 호출문을 만나면 getTotal을 위한 실행 컨텍스트를 생성하고 Call Stack에 넣는다. 이때, 글로벌 스코프에서 getTotal에 대한 식별자 해결을 진행하고 Function Object가 들고 있던 외부 환경을 들고와서 외부 렉시컬 환경 참조에 설정한다.
  3. getMyValue 실행 컨텍스트 초기화 단계가 진행되면서 내부에 있던 변수나 함수들이 선언적 환경 레코드에 설정된다.
  4. 초기화 단계가 끝나면 코드가 실행된다.



2. VEC (Variable Environment Component)

  • 렉시컬 환경과 변수 환경 컴포넌트의 초기 값은 같다.
    변수 환경 컴포넌트는 렉시컬 환경의 복원을 위해 존재한다. 렉시컬 환경은 정적환경이지만, 글로벌 환경과 동적 환경이 이 안에서 처리되기 때문에, 세부 값의 변경이 일어날 수 있다. 함수가 다시 실행될 때, 실행 컨텍스트를 새로 만들고 초기화 하는 것보 변수 환경의 값을 렉시컬 환경에 적용함으로써 초기값으로 돌아가는 것이 더 효율적이다.



3. TBC (This Binding Component)

this란?

this는 Javascript의 키워드다. obj.aa() 형태로 호출한 함수(메소드) aa 에서는 this로 인스턴스(오브젝트)를 참조할 수 있다. 메소드가 호출될 때 객체가 실행 컨텍스트의 This 바인딩 컴포넌트에 바인딩된다. 따라서, 함수 내부에서 this 키워드로 객체를 참조하여 obj의 변수나 함수를 사용할 수 있다.

  • 이후, this 관련하여 자세한 글을 포스팅을 하겠습니다.

TBC의 쓰임

  • this 키워드를 사용하여 함수를 호출한 오브젝트에 접근할 수 있도록, 함수의 실행 컨텍스트안에 해당 오브젝트를 참조하는 공간을 둔 것이 TBC다.
  • 우리는 외부 렉시컬 환경 참조를 통해 함수 바로 바깥에 있는 것들에 접근할 수 있으며, 선언적 환경 레코드를 통해 함수 내부에 있는 것들에 접근할 수 있다. 함수 내외부 뿐만아니라, TBC를 통해 this를 통해 다른 객체에도 접근이 가능하다.

this는 동적으로 결정된다.

call(), apply(), bind() 등의 메소드를 통해 this로 참조할 객체를 변경할 수 있으며, this로 참조할 객체는 호출 시점에 결정된다고 알고 있을 것이다. 즉 동적으로 결정된다. 이것이 가능한 이유는 TBC는 동적으로 바인딩되기 때문이다.


Example

var obj = {value : 1000}
function getValue(){
  var something = 999
  return this.value
}

getValue() 
//=> this가 global로 binding 됨 
//=> undefined 출력

getValue.call(obj)
//=> this 바인딩 컴포넌트에 obj의 scope가 들어온다.
//=> 1000 출력
getValue.call(obj)일 때 실행컨텍스트
getValue 컨텍스트 : {
    환경 레코드 : {
        선언적 환경 레코드 : { something : 999 },
        외부 렉시컬 환경 참조 : { obj : Object }
     },
     오브젝트 환경 레코드 : { },
     this바인딩 컴포넌트 : { value : 1000 }
}



Next..

외부 렉시컬 환경 참조를 설정 과정을 이해하기 위해, JS 엔진이 Function Object를 처리하는 방식에 대해 포스팅 하겠습니다.

profile
한국외대 중국어&컴공 복수전공 - 세미 전공자의 기술 블로그

0개의 댓글