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

김진서·2025년 5월 9일

우아한테크코스 7기

목록 보기
39/56
post-thumbnail

👉 ‘코어 자바스크립트’의 ‘02 실행 컨텍스트’를 읽으며 기억할 내용들과 새로 알게 된 내용을 정리하였습니다.

🔽 2-1 실행 컨텍스트란?


  • 실행 컨텍스트(execution context): 실행할 코드에 제공할 환경 정보들을 모아놓은 객체.
    • 자바스크립트는 어떤 실행 컨텍스트가 활성화되는 시점에 선언된 변수를 위로 끌어올리고(호이스팅), 외부 환경 정보를 구성하고, this 값을 설정하는 등의 동작을 수행.
    • 동일 환경에 있는 코드들을 실행할 때 필요한 환경 정보들을 모아 컨텍스트를 구성하고, 이를 콜 스택(call stack)에 쌓아올렸다가, 가장 위에 쌓여있는 컨텍스트와 관련 있는 코드들을 실행하는 식으로 전체 코드의 환경과 순서 보장.
    • 우리가 흔히 실행 컨텍스트를 구성하는 방법은 함수를 실행하는 것 뿐.
  • 예를 들어, js 콜 스택의 최대 용량을 넘기면 에러를 throw.
    var eternalLoop = function() {
    	return eternalLoop();
    }
    
    // Uncaught RangeError; Maximum call stack size exceeded
    실행 컨텍스트와 콜 스택 예시:
    // ------------------------------ (1)
    var a = 1;
    function outer() {
    	function inner() {
    		console.log(a); // undefined
    		var a = 3;
    	}
    	inner(); // ------------------- (2)
    	console.log(a);  // 1
    }
    outer();  // -------------------- (3)
    console.log(a);    // 1
    위 코드에 대한 설명.
    1. (1) 자바스크립트 코드를 실행하는 순간 전역 컨텍스트가 콜 스택에 push.

    2. (3) outer 함수를 호출하면 자바스크립트 엔진은 outer에 대한 환경 정보를 수집해서 outer 실행 컨텍스트를 생성한 후 콜 스택에 push. (콜 스택 맨 위에 outer 실행 컨텍스트가 놓인 상태가 됐으므로, 전역 컨텍스트와 관련된 코드의 실행을 일시 중단하고 대신 outer 실행 컨텍스트와 관련된 코드, 즉 outer 함수 내부의 코드들을 순차적으로 실행)

    3. (2) inner 함수의 실행 컨텍스트가 콜 스택의 가장 위에 담기면 outer 컨텍스트와 관련된 코드의 실행을 중단하고 inner 함수 내부의 코드를 순서대로 진행.

    4. inner 함수 실행 종료되면 콜 스택에서 제거.

    5. 아래에 있던 outer 컨텍스트가 콜 스택 맨 위에 존재하게 되므로, (2)의 다음줄부터 이어서 실행.

    6. a 변수 출력하면 outer 실행 컨텍스트가 콜 스택에서 제거되고, 전역 컨텍스트만 존재.

    7. 실행을 중단했던 (3) 다음줄 이어서 실행.

    8. a 변수 값 출력하면 전역 공간에 실행할 코드가 없어 전역 컨텍스트도 제거. 콜 스택 비어진 채로 종료.

      실행 컨텍스트가 활성화 될 때 자바스크립트 엔진은 해당 컨텍스트에 관련된 코드들을 실행하는데 필요한 환경 정보들을 수집해서 실행 컨텍스트 객체에 저장.

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

🔽 2-2 VariableEnvironment


  • VariableEnvironment에 담기는 내용은 LexicalEnvironment와 같지만, 최초 실행 시의 스냅샷을 유지한다는 점이 다르다.
  • 실행 컨텍스트를 처음 생성할 때 VariableEnvironment에 정보를 먼저 담고, 이를 그대로 복사해서 LexicalEnvironment를 만들고, 이후에는 LexicalEnvironment를 주로 활용한다.
  • 내부는 environmentRecordouterEnvironmentReference로 구성되어있다.

🔽 2-3 LexicalEnvironment


  • 2-3-1 environmentRecord와 호이스팅

    • environmentRecord: 현재 컨텍스트와 관련된 코드의 식별자 정보 저장.

      • 호이스팅(hoisting): 매개변수 식별자,함수 선언문, 변수 식별자 등 컨텍스트 내부 전체를 처음부터 스캔하며, 수집.
      function a (x) {  // 수집 대상 1(매개변수)
      	console.log(x);  // (1)
      	var x;  // 수집 대상 2(변수 선언)
      	console.log(x);  // (2)
      	var x = 2;  // 수집 대상 3(변수 선언)
      	console.log(x);  // (3)
      }
      a(1);

      호이스팅이 되지 않을 때 예상 값: (1) - 1, (2) - undefined, (3) - 2
      실제: (1) - 1, (2) - 1, (3) - 2

      function a () {
      	console.log(b);  // (1)
      	var b = 'bbb';  // 수집 대상 1(변수 선언)
      	console.log(b);  // (2)
      	function b () { }  // 수집 대상 2(함수 선언)
      	console.log(b);  // (3)
      }
      a();

      호이스팅이 되지 않을 때 예상 값: (1) - undefined, (2) - ‘bbb’, (3) - function b
      실제: (1) - function b, (2) - ‘bbb’, (3) - ‘bbb’

      함수 선언문, 함수 표현식

      function a () { }  // 함수 선언문. 함수명 a가 곧 변수명.
      a();  // 실행 OK.
      
      var b = function () { }  // 익명 함수 표현식. 변수명 b가 곧 함수명.
      b();  // 실행 OK.
      
      var c = function d () { }  // 기명 함수 표현식. 변수명은 c, 함수명은 d.
      c();  // 실행 OK.
      d();  // 에러!
      • 함수 선언문은 전체를 호이스팅하지만, 함수 표현식은 변수 선언부만 호이스팅 한다.
        • 함수를 변수값에 할당한 것.
        • 상대적으로 함수 표현식이 좀 더 안전하다.
  • 2-3-2 스코프, 스코프 체인, outerEnvironmentReference

    • 스코프(scope): 식별자에 대한 유효범위.

      • 함수 스코프: 함수에 의해서 생성된 스코프.
      • 블록 스코프: 블록에 의해서 생성된 스코프(let, const, class, strict mode 함수 선언 등).

      스코프 체인(scope chain)

      : 식별자의 유효범위를 안에서부터 바깥으로 차례로 검색해나가는 것.

      outerEnvironmentReference

      : 현재 호출된 함수가 선언될 당시LexicalEnvironment를 참조.

      • A 함수 내 B 함수, B 함수 내 C 함수 선언 시 함수 C의 outerEnvironmentReference가 함수 B의 LexicalEnvironment를 참조하고, 함수 B의 outerEnvironmentReference가 함수 A의 LexicalEnvironment를 참조.
      • outerEnvironmentReference는 linked list 형태
        • 가장 가까운 요소로부터 차례대로만 접근할 수 있고, 다른 순서로 접근하는 것은 불가능.
        • 이에 따라 여러 스코프에서 동일한 식별자 선언 시 무조건 스코프 체인 상에서 가장 먼저 발견된 식별자에만 접근 가능
      • 변수 은닉화(variable shadowing): 함수에서 선언한 변수는 외부의 동일한 이름의 변수에 접근할 수 없다.

      💡 크롬 브라우저 환경에서 스코프 체인 중 현재 실행 컨텍스트를 제외한 상위 스코프 정보를 개발자 도구의 콘솔로 확인 가능.
      console.dir(함수명); ⇒ 함수 내부에서 실제로 호출할 외부 변수들의 정보만 노출. ⇒ 브라우저 성능 향상 목적.

      전역변수, 지역변수

      • 전역변수(global variable): 전역 공간에서 선언한 변수.
      • 지역변수(local variable): 함수 내부에서 선언한 변수는 무조건 지역변수.
      • 코드의 안전성을 위해 가급적 전역변수 사용 최소화.

🔽 2-4 this


실행 컨텍스트의 ThisBinding에는 this로 지정된 객체가 저장. 실행 컨텍스트 활성화 당시에 this가 지정되지 않은 경우 this에는 전역 객체가 저장. 함수를 호출하는 방법에 따라 this에 저장되는 대상이 다르다.

🔽 2-5 정리


✅실행 컨텍스트 객체는 활성화되는 시점에 VariableEnvironment, LexicalEnvironment, ThisBinding의 3가지 정보 수집.

✅ 생성 시에는 VariableEnvironmentLexicalEnvironment가 동일하지만, LexicalEnvironment는 함수 실행 도중에 변경되는 사항이 즉시 반영되나, VariableEnvironment는 초기 상태 유지.

✅ LexicalEnvironment는 매개변수명, 변수 식별자, 선언한 함수명 등을 수집하는 environmentRecord와 바로 직전 컨텍스트의 LexicalEnvironment 정보를 참조하는 outerEnvironmentRecord로 구성.

profile
PAy IT forwaRD를 실천하는 프론트엔드 개발자.

0개의 댓글