Execution Context [3] - Function Object

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

JS 엔진의 컨텍스트 처리 흐름

  1. 컨텍스트 생성 및 Call Stack에 컨텍스트 push
  2. 컨텍스트 초기화 단계
    코드를 실행하기 전에 엔진은 초기화 단계를 진행한다. 컨텍스트의 코드를 순회하면서 변수나 함수를 초기화한다. 순회할 때, function키워드를 만나면 Function Object를 생성하고 각종 정보를 설정한다.
  3. 코드 실행

엔진이 function키워드를 만나 Function Object를 생성하는 과정을 살펴보면, 실행 컨텍스트의 외부 렉시컬 참조가 어떻게 설정되는지 알 수 있다.

Javascript의 Function

  • 자바스크립트의 함수는 일급 객체다. 일급객체 함수는 일반적인 객체와 다르지 않아서 함수의 인자로 함수를 넘길 수 있고, 함수의 반환 값이 될 수도 있다.
  • 자바스크립트에는 built-in Function Object가 존재한다. 따라서 우리는 new 키워드를 이용해서 함수 객체를 만들 수 있다.
  • JS에서 어떤 객체를 함수로 사용하려면, 그 객체는 Function Object여야 한다.


Function Object 생성

  • 엔진의 코드 해석 단계에서 var test = function()이라는 문장을 만나면(function 키워드를 만나면), built-in Function Object의 prototype에 연결된 메소드로 Function Object를 생성한다.
    • 여기서 생성된 것은 인스턴스지만, new키워드로 만든 Function 인스턴스와는 차이가 있다.
  • 생성한 Function Object를 test라는 변수에 할당해준다.
  • 이후에 test()라는 코드를 만났을 땐, 식별자 해결을 통해 test 변수가 Function Object라는 것을 알게 되면 호출을 진행하게 된다.


Function Object 저장

실행 컨텍스트 : {
   렉시컬 환경 : {
       선언적 환경 레코드 : {
           함수명 : Function Object,
           변수명 : 값,
        }
   }
}
  • 함수를 호출하려면, 먼저 식별자 해결을 통과하기 위해 함수명을 현재 Scope의 선언적 환경 레코드에 설정해야 한다. 이후 함수명의 value 값으로 생성한 function object를 저장해야 한다.
    우리가 function 키워드를 사용해서 함수를 선언하면, JS엔진이 함수명 : Function Object의 형태로 변경해준다. 따라서 우리가 함수명() 형태로 함수를 호출하면, 엔진은 Scope를 뒤져가며 함수명으로 식별자 해결을 진행한다. 식별자 해결을 하여 함수 이름이 가진 value가 Function Object가 맞다면 비로소 호출을 진행한다.


Execution Context의 참고자료 = Function Object

  1. 개발자가 function test(){...} 키워드를 사용해서 함수를 선언
  2. 엔진이 function 키워드를 만나면, Function Object를 생성하고 {sports : {...}}의 형태로 저장한다. 이때 value인 Function Object의 내용물은 비어있다.

우리는 Lexical Environment의 "외부 렉시컬 참조를 통해" 함수 바로 바깥에 있는 변수에 접근할 수 있다. 지금 비어진 Function Object에 함수가 속한 Scope를 설정해둔다. 이후 함수가 호출되는 시점에 엔진은 Function Object의 내용물을 기반으로 실행 컨텍스트의 "외부 렉시컬 참조"가 설정한다.

  • 함수가 속한 Scope를 그냥 Function Object에 넣는 것이 아니라, 내부 프로퍼티 [[Scope]]의 value로 저장한다.

내부 프로퍼티란?

내부 프로퍼티란 일반 프로퍼티와 달리, 엔진이 내부적인 처리를 위해 사용하는 프로퍼티로 개발자가 접근할 수 없는 프로퍼티다. 내부 프로퍼티는 [[Scope]] : { }와 같이 중괄호 두개로 표현된다.
built-in Object들이 모두 가지고 있는 내부 프로퍼티를 "공통 프로퍼티"라고 하며, built-in Object의 종류마다 다른 처리를 위해 달리 들고 있는 프로퍼티를 "선택적 프로퍼티"라고 한다.

  • 현재의 Scope는 Function Object에 [[Scope]] : {...환경} 의 형태로 저장되어 외부 렉시컬 참조의 설정 때 쓰인다.
  • 엔진이 Function Object를 만들 때, Function Object 내부 프로퍼티 [[Code]]에 함수 내부의 코드들을 저장해둔다.
  • 함수의 인자들 또한 내부 프로퍼티로 저장되어 있다가, 실행 컨텍스트로 만들어지는 시점에서 파라미터 변수와 인자들을 맵핑하는 단계를 거치기도 한다.

즉, function 키워드가 존재하는 컨텍스트의 선언적 환경 레코드에 함수명 : Function Object의 형태로 저장되며, 현재의 Scope는 Function Object에 [[Scope]] : {...환경} 의 형태로 저장되어 외부 렉시컬 참조의 설정 때 쓰인다.




Scope Binding

Binding 이란?

  • binding의 목적은 스코프를 설정하여 식별자 해결을 진행할 수 있도록 만드는 것이다.
  • binding되는 시점을 기준으로 정적 바인딩(Lexical Binding)동적 바인딩(Dynamic Binding)으로 나눌 수 있다.

Lexical Binding Javascript

Function Object가 생성되면서, 내부 프로퍼티 [[Scope]]에 타겟 함수의 Scope를 설정해둔다. 이렇게 설정된 Scope는 절대 변경되지 않는다. 따라서 자바스크립트는 "정적 Scope", "정적 환경"이라고 부를 수 있다.

우리는 apply()와 같은 메소드를 사용해서 This 바인딩 컴포넌트가 참조하는 대상을 동적으로 변경할 수 있었다. 이처럼 외부 렉시컬 참조가 가지는 Scope를 동적으로도 변경할 수"도" 있다.
with문, eval()등으로 Scope를 동적으로 변경 가능하다.




함수 표현식과 함수 선언문

Function Object 생성 시점의 차이

사실 실행 컨텍스트의 초기화 단계는 더 세분화된다.

  1. 엔진은, 먼저 함수 내부에 있는 함수 선언문을 모두 추려낸다.
  2. "함수 선언문"을 작성된 순서대로 해석한다.
  3. 모든 "함수 선언문"의 해석이 끝났으면, 모든 표현식을 추려낸다.
    • var a = 123; 과 var b = function(){}는 모두 표현식이다.(변수에 할당하는 형태는 모두 표현식이다.)
    • 함수 표현식은, 할당되는 것이 Function Object인 경우를 말하는 것이다.
  4. 작성한 순서대로 모든 표현식을 해석한다.
    • rValue를 lValue로 할당하지는 않는다. lValue = Undefined로 해석해둔다. 그저 메모리 공간을 확보하는 작업만한다.

따라서 함수 선언문들은 초기화 단계에서 Function Object가 생성되면서 Scope가 결정되지만, 함수 표현식의 경우 함수명 : Undefined로 환경에 설정되어 있다가 코드가 실행되는 단계에서 Function Object가 생성되어 Scope가 결정된다.

Example

function book() {
  var title = "타이틀";

  function getBook() {
    return title;
  }
  var readBook = function () {};
  getBook();
}
book();
  1. book() 함수 호출로 내부로 진입
  2. 엔진은 book 함수 내부를 한 바퀴 돌면서, 함수 선언문만 해석
    • Scope를 생성하여 각 function Object의 [[Scope]] 에 넣어주는 단계
    1. function getBook(){};
  3. 선언문 해석이 끝나면, 엔진은 다시 book함수의 첫번째 줄로 돌아온다. 엔진은 표현식만을 해석한다,
    • 이때, 변수 선언(메모리 공간 확보)을 한다. 또한 엔진은, 확보된 공간에 담긴 변수의 값으로 undefined를 할당한다.
    1. var title = undefined;
    2. var readBook = undefined;
  4. 코드 실행
    • var title = "타이틀";
    • var readBook = function(){};
      • 표현식의 function Object는 실행 단계에서 생성된다. function Object가 생겼으므로, 호출이 가능해진다.
    • getBook();
profile
한국외대 중국어&컴공 복수전공 - 세미 전공자의 기술 블로그

0개의 댓글