JavaScript - 실행 컨텍스트

euNung·2022년 6월 26일
0

JavaScript

목록 보기
2/7
  • 자바스크립트는 어떤 실행 컨텍스트가 활성화되는 시점에 다음과 같은 동작 수행
    1) 변수를 위로 끌어올림(호이스팅)
    2) 외부 환경 정보를 구성
    3) this 값을 설정

  • 실행 컨텍스트
    : 실행할 코드에 환경 정보들을 모아놓은 객체

    1) 동일한 환경에 있는 코드들을 실행할 때 필요한 정보들을 모아 컨텍스트를 구성
    2) 이를 콜 스택에 쌓아올림
    3) 가장 위에 쌓여있는 컨텍스트와 관련있는 코드들을 실행하는 식으로 전체 코드의 환경과 순서 보장

    🧡 실행 컨텍스트를 구성할 수 있는 방법

    • 전역공간: 자동으로 생성
    • eval() 함수: 악마로 취급받음 ...?
    • 함수: 우리가 흔히 실행 컨텍스트를 구성하는 방법
// (1), (6)
var a = 1;
function outer() {
  function inner() {
    console.log(a);
    var a = 3;
  }
  inner();           // (3), (4)
  console.log(a);
}
outer();             // (2), (5)
console.log(a);

(1) 처음 자바스크립트 코드를 실행하는 순간 전역 컨텍스트가 콜 스택에 담김
(2) outer 함수를 호출하면 자바스크립트 엔진이 outer에 대한 환경 정보를 수집해서 otuer 실행 컨텍스트를 생성한 후 콜 스택에 담음
(3) inner 함수의 실행 컨텍스트가 가장 위에 담기면 outer 컨텍스트와 관련된 코드의 실행을 중단하고 inner 함수 내부의 코드를 순서대로 진행
(4) inner 함수 내부에서 a 변수에 값을 할당하고 나면 inner 함수의 실행이 종료되면서 inner 실행 컨텍스트가 콜 스택에서 제거
(5) a 변수의 값을 출력한 후 outer 함수의 실행이 종료되어 outer 실행 컨텍스트가 콜 스택에서 제거
(6) a 변수의 값을 출력한 후 전역 공간에 더는 실행할 코드가 남아있지 않아 전역 컨텍스트도 제거되고, 콜 스택에는 아무것도 남지 않은 상태로 종료


  • 실행 컨텍스트의 환경 정보
    • VariableEnvironment
      : 현재 컨텍스트 내의 식별자에 대한 정보 + 외부 환경 정보
      ➡ (environmentRecord + outerEnvironmentReference로 구성)
      : 선언 시점의 LexicalEnvironment의 스냅샷으로, 변경 사항 반영x
    • LexicalEnvironment의
      : 처음에는 VariableEnvironment와 같지만 변경 사항이 실시간으로 반영됨
      : environmentRecord + outerEnvironmentReference로 구성
    • ThisBinding
      : this 식별자가 바라봐야 할 대상 객체

🧡 실행 컨텍스트를 생성할 때 VariableEnvironment에 정보를 먼저 담은 다음, 이를 그대로 복사해서 LexicalEnvironment를 만들고, 이후에는 LExicalEnvrionment를 주로 활용


  • LexicalEnvironment
    "현재 컨텍스트의 내부에는 a, b, c와 같은 식별자들이 있고 그 외부 정보는 D를 참조하도록 구성되어 있다"

    • environmentRecord
      : 현재 컨텍스트와 관련된 코드의 식별자 정보들이 저장
      ex) 컨텍스트를 구성하는 함수에 지정된 매개변수 식별자, 선언한 함수가 있을 경우 그 함수 자체, var로 선언된 변수의 식별자 등

    • 호이스팅
      : 변수 정보를 수집하는 과정을 모두 마쳤더라도 아직 실행 컨텍스트가 관여할 코드들을 실행되기 전의 상태
      => '자바스크립트 엔진은 식별자들을 최상단으로 끌어올려놓은 다음 실제 코드를 실행한다'라고 생각해도 코드를 해석하는 데 문제x
      => 자바스크립트 엔진이 실제로 끌어올리지는 않지만 편의상 끌어올린 것으로 간주

      • environmentRecord는 현재 실행될 컨텍스트의 대상 코드 내에 어떤 식별자들이 있는지에만 관심이 있고, 각 식별자에 어떤 값이 할당될 것인지는 관심x
        => 변수를 호이스팅 할 때 변수명만 끌어올리고 할당 과정은 원래 자리에 그대로 남겨둠

💛 매개변수와 변수에 대한 호이스팅

			function a(x) {
              console.log(x);
              var x;				// (2)
              console.log(x);
              var x = 2;			// (3)
              console.log(x);
            }
			a(1);					// (1)

			// 호이스팅 된 상태
			function a(x) {
              var x;				// (1)의 변수 선언
              var x;				// (2)의 변수 선언
              var x;				// (3)의 변수 선언
              
              var x = 1;			// (1)의 할당
              console.log(x);
              console.log(x);
              var x = 2;			// (3)의  할당
              console.log(x);
            }
			a();

			/* 실행 결과
            1
            1
            2
            */

💛 함수 선언의 호이스팅

			function a() {
              console.log(b);
              var b = 'bbb';			// (2)
              console.log(b);
              function b() { }			// (1)
              console.log(b);
            }
			a();

			// 호이스팅 된 상태
			function a() {
              var b;					// 변수는 선언부만 끌어올림
              function b() { }			// 함수 선언을 전체를 끌어올림
              
              console.log(b);
              b = 'bbb';				// (2)의 할당
              console.log(b);
              console.log(b);
            }
			a();

			/* 실행 결과
            f b() { }
            'bbb'
            'bbb'
            */

  • 함수 선언문
    : function 정의부만 존재하고 별도의 할당 명령이 없는 것
  • 함수 표현식
    : 정의한 function을 별도의 변수에 할당하는 것
// 함수 선언문
function sum(a, b) {
  return a + b;
}

// 함수 표현식
var multiply = function (a, b) {
  return a * b;
}
  • 함수 선언문 & 함수 표현식 호이스팅
console.log(sum(1, 2));
console.log(multiply(3, 4));

function sum(a, b) {
  return a + b;
}

var multiply = function (a, b) {
  return a * b;
}

// 호이스팅 된 상태
var sum = function sum (a, b) {		// 함수 선언문은 전체를 호이스팅
  return a + b;
};

var multiply;						// 변수는 선언부만 끌어오림

console.log(sum(1, 2));
console.log(multiply(3, 4));

multiply = function (a, b) {		// 변수의 할당부는 원래 자리에 남겨둠
  return a + b;
};

💙 함수 선언문은 선언 전에 호출해도 아무 문제 없이 실행되므로 혼란을 일으킬 수 있기 때문에 함수 표현식 사용을 더 추천


  • 스코프
    : 식별자에 대한 유효범위
  • 스코프 체인
    : '식별자의 유효범위'를 안에서부터 바깥으로 차례로 검색해나가는 것

    • outerEnvironmentReference는 현재 호출된 함수가 선언될 당시의 LexicalEnvrionment를 참조
// (1)
var a = 1;
var outer = function () {
  var inner = function () {
    console.log(a);
    var a = 3;
  }
  inner();           // (3)
  console.log(a);
}
outer();             // (2)
console.log(a);

(1) 전역 컨텍스트
- environmentRecord: { a, outer }
- outerEnvrionmentReference: 아무것도 담기지 않음
- this: 전역 객체

(2) outer 실행 컨텍스트
- environmentRecord: { inner }
- outerEnvrionmentReference: { GLOGBAL, { a, outer } }
=> outer 함수가 선언될 당시(전역 컨텍스트)의 LexicalEnvironment가 담김
- this: 전역 객체

(3) inner 실행 컨텍스트
- environmentRecord: { a }
- outerEnvrionmentReference: { outer, { inner } }
=> inner 함수가 선언될 당시(outer 실행 컨텍스트)의 LexicalEnvironment가 담김
- this: 전역 객체

  • this
    : 실행 컨텍스트의 thisBinding에는 this로 지정된 객체가 저장됨
    : 실행 컨텍스트 활성화 당시에 this가 지정되지 않은 경우 this에는 전역 객체가 저장됨
    : 그 외의 경우 함수를 호출하는 방법에 따라 this에 저장되는 대상이 다름
profile
프론트엔드 개발자

0개의 댓글