본문 바로가기

프로그래밍 언어/Javascript

Javascript) 자바스크립트의 핵심 원리 : 실행 컨텍스트 Execution Context

실행 컨텍스트란?

  • ECMAScript 스펙에 따르면 실행 컨텍스트는 실행 가능한 코드를 형상화하고 구분하는 추상적인 개념이다. 즉, 코드가 실행되기 위해 필요한 환경을 말한다.
  • 하나의 컨텍스트는 하나의 동작을 실행하는 환경으로 이와 관련 없는 함수나 변수 등의 코드를 만나게 되면 새로운 컨텍스트를 생성한다. 그리고 이 컨텍스트들은 한번에 하나의 동작만 처리하는 자바스크립트의 콜백 스택에 쌓이게 된다. 
  • 자바스크립트 엔진의 동작 방식은 다음과 같다.  
    1. 실행 가능한 코드 (잔역 코드, 함수 내 코드 등)를 만나면 실행 컨텍스트 스택이 생성된다. 
      1. 전역 코드가 스택에 들어오면 전역 실행 컨텍스트가 생성되어 스택에 쌓인다. 전역 실행 컨텍스트는 해당 애플리케이션이 종료될때까지 유지된다. 
      2. 함수가 호출되면 이 함수를 위한 실행 컨텍스트가 생성되어 스택에 쌓이고 함수가 값을 반환하거나 종료되면 해당 함수의 실행 컨텍스트가 소멸되고 스택에서 pop 하게 되고 스택에서 바로 직전의 실행 컨텍스트에 제어권이 돌아간다. 
    2. 실행 제어권은 항상 스택의 top 최상위에 있는 실행 컨텍스트가 갖는다. 

 

실행 컨텍스트 객체의 프로퍼티 

실행 컨텍스트는 실행 가능한 코드를 형상화하고 구분하는 추상적인 개념, 즉, 어떤 코드의 동작 한 덩어리이다. 이는 물리적으로 객체의 형태를 가지며 다음과 같은 프로퍼티를 갖는다.

변수 객체 Variable Object 

  • 실행 컨텍스트가 생성되면 자바스크립트 엔진은 실행에 필요한 정보들을 담을 객체인 변수 객체를 생성한다. 그 변수 객체에 코드에서 선언된 변수, 함수에 전달된 인자, 함수 선언 (function()...) 을 담아 엔진이 코드를 실행할 때 참조한다. 
  • 그런데 이때 실행 컨텍스트가 전역 컨텍스트인 경우와 함수 컨텍스트인 경우 변수 객체가 가리키는 객체가 다르다.
    • 전역 컨텍스트일 경우, 변수 객체는 유일하며 최상위에 위히하고 모든 전역 변수, 전역 함수등을 포함하는 전역 객체 (Global object)를 가리킨다. 전역 객체는 글로벌로 선언된 변수와 함수를 프로퍼티로 갖는다. (변수 객체 = 전역 객체) 
    • 함수 컨텍스트일 경우,  변수 객체는 활성 객체 (Activation object)를 가리키며 인자들의 정보를 배열로 담고 있는 객체인 argument object가 추가된다.  (변수 객체 = 활성 객체 + 인자 배열 객체)

스코프 체인 Scope chain

  • 간단히 말하자면 변수 객체에 담긴 정보들의 리스트를 말한다. 
  • 전역 객체 또는 활성 객체들이 담겨있다. 
  • 실행 컨텍스트의 활성 객체를 선두로 순차적으로 스택의 상위에 있는 실행 컨텍스트의 활성 객체를 가리키며 마지막으로 전역 객체를 가리킨다. 즉, 실행 컨텍스트 스택의 top->bottom순서! 
  • 엔진은 스코프 체인을 통해 렉시컬 스코프를 파악한다.
  • 중첩 함수의 경우 부모 함수의 스코프 체인이 자식 함우의 스코프 체인에 포함된다. 
  • 함수 실행 중 변수를 만나면 그 변수를 현재 스코프에서 검색하는데 그 변수를 찾을 때가지 스코프 체인을 순서대로 검색한다. 만약 끝까지 스코프 체인에서 변수를 찾아내지 못하면 정의되지 않은 변수에 접근하는 것으로 판단하여 Reference 에러가 발생한다. 
  • 함수의 Scope 프로퍼티로 조회할 수 있다. 

this value 

 

Javascript) this 용법

자바스크립트 함수는 호출될 때, 매개변수로 전달되는 인자값 외에 arguments 객체와 this를 암묵적으로 전달받는다.  Java에서 this는 객체 자기 자신을 참조하는 변수 Javascript에서 this는 함수 호출

seungyooon.tistory.com

 

 

실행 컨텍스트의 생성 과정  

  1. 전역 객체가 생성된다.  
    • Global Object = 전역 컨텍스트의 VO가 가리키는 객체
    • 전역 객체는 코드 어떠한 곳에서도 접근할 수 있다. 
    • 생성된 직후 초기 상태에는 DOM, BOM, 빌트인 객체등이 설정되어 있다. 
  2. 코드를 만나면 실행 컨텍스트가 생성되고 이것이 실행 컨텍스트 스택에 쌓이고 생성된 실행 컨텍스트를 바탕으로 다음과 같은 처리가 이루어진다. 
    • 스코프 체인 생성 및 초기화 : 전역 객체의 레퍼런스를 포함하는 리스트 
    • 변수 객체화 : 객체 변수에 프로퍼티와 값을 추가하는 것   
      • 전역 실행 컨텍스트의 경우 객체 변수가 전역 객체를 가리킨다. 
      • 변수 객체화 실행 순서 (반드시 이 순서대로 실행됨) 
        1. 함수 실행 컨텍스트인 경우 변수 객체가 매개변수(키/프로퍼티) - 인자(밸류)를 가진다. 
        2. 함수 표현식이 아닌 함수 선언 자체의 함수명이 변수 객체의 프로퍼티가 되고 생성된 함수 객체가 값으로 설정된다. (=함수 호이스팅) 
        3. 코드 내 변수가 변수 객체의 프로퍼티가 되고 undefined가 값이 된다 (변수 호이스팅) 
        변수 객체 = {
        	parameter : argument,
            	function_name : function() object,
            	variable_name : undefined
        }​
  3. 함수 선언 처리 
    • 전역 실행 컨텍스트의 변수 객체가 가리키는 전역 객체는 함수들의 이름을 프로퍼티로 가지고 있고, 각 함수 이름 프로퍼티들은 함수객체들을 값으로 가진다. 
    • 이때 함수 이름 프로퍼티의 값으로 설정된 함수 객체들은 스코프 프로퍼티를 갖는다. 이 스코프 프로퍼티는 햄수 객체가 실행되는 환경으로 현재 실행 컨텍스트의 스코프 체인이 참조하고 있는 객체를 값으로 설정한다. 즉, 현재 함수 실행 컨텍스트의 스코프 체인이 전역 객체 내 함수 프로퍼티의 값인 함수 객체의 스코프 프로퍼티 값과 일치하는 것! 
    • 내부 함수의 스코프 프로퍼티는 자신의 실행환경 (=렉시컬 환경) + 외부 함수의 실행환경 + 전역 객체를 가지는데 클로저 현상으로 인해 외부 함수 실행 컨텍스트가 소멸하여도 내부 함수 스코프의 프로퍼티가 가리키는 외부 함수의 실행환경, 활성 객체는 소멸하지 않고 계속 참조할 수 있다. 
    • 이렇게 스코프 체인이 가리키는 변수 객체에 이미 함수이름을 프로퍼티로, 해당 함수 객체를 그 값으로 가지고 있기 때문에 함수 선언 코드가 아직 실행되지 않아도 그 이전에 이 함수를 호출할 수 있다 = 함수 호이스팅 
  4. 변수 선언 처리 
    • 변수들은 변수 객체화를 하면서 변수 명을 변수객체의 프로퍼티 이름으로, undefined를 값으로 설정되는데 그 과정을 좀 더 세분화 해보면 다음과 같다. 
      1. 선언 declaration : 변수 객체에 변수를 등록하여 스코프 참조 대상이 된다. 
      2. 초기화 initialization : 변수 객체에 등록된 변수를 메모리에 할당하면서 그 값을 undefined로 초기화한다. 
      3. 할당 assignment : undefined로 초기화된 변수에 실제 코드에서 할당된 값을 할당한다.
    • var 키워드로 선언된 변수는 선언과 초기화가 한번에 일어나 변수 선언 코드를 만나기 이전에도 해당 변수가 변수 객체에 존재하기 때문에 접근할 수 있다. 다만 이것은 undefined로 반환된다 ( = 변수 호이스팅) 그러다 var 변수에 값을 할당하는 코드를 만나면 값의 할당 (3단계)이 이루어진다. 
  5. this value 결정 
    • this value는 전역 컨텍스트에서 전역 객체를 가리키고 있다가 함수 호출 패턴에 의해 this 에 값이 할당된다. 
  6. 전역 코드 실행 
    • 현재 실행 컨텍스트의 스코프 체인이 참조하고 있는 객체 변수 리스트(=전역 객체들)를 검색하면서 해당 변수명 프로퍼티를 찾는다. 발견하면 값을 할당하고 없으면 레퍼런스 에러를 발생시킨다. 
    • 함수 실행 코드를 만나면 새로운 함수 실행 컨텍스트가 생성된다. 그럼 위와 동일하게 함수 컨텍스트에 대한 스코프 체인을 생성 및 초기화하고 변수 객체화를 하고, this value를 결정한다. 
      1. 함수의 스코프 체인 생성과 초기화 : 활성 객체에 대한 레퍼런스를 스코프 체인의 선두에 둔다. 활성 객체들은 파라미터를 프로퍼티 이름으로 설정한다. 그리고 부모가 되는 컨텍스트가 참조하는 스코프 체인도 이 함수 스코프 체인에 push된다. 
      2. 스코프 체인에 들어가 있는 활성 객체들의 프로퍼티들에 실제 값을 할당한다. 
      3. 함수 호출 패턴에 의해 this 값을 결정한다. 
  7. 함수 코드 실행 
    • 함수 내 변수 값 할당 : 현재 함수 실행 컨텍스트의 스코프 체인이 참조하고 있는 변구 객체 (리스트)를 앞에서부터 검색하며 변수명에 해당하는 프로퍼티를 발견하면 거기에 값을 할당한다. 
    • 함수 내 함수 실행 : 새로운 함수 실행 컨텍스트를 생성하고 스택에 쌓는다. 함수 실행 컨텍스트의 실행 과정과 동일한 단계들이 순차적으로 진행된다. 

 


References