Skip to content

Latest commit

 

History

History
414 lines (285 loc) · 18.1 KB

File metadata and controls

414 lines (285 loc) · 18.1 KB
  • 실행 컨텍스트는 자바스크립트의 동작 원리를 담고 있는 핵심 개념

23.1 소스코드의 타입

소스코드의 타입 설명
전역 코드 전역에 존재하는 소스코드, 함수나 클래스 등의 내부 코드는 포함 X
함수 코드 함수 내부에 존재하는 소스코드, 중첩된 함수, 클래스 등의 내부 코드는 포함 X
eval 코드 eval 함수에 인수로 전달되어 실행되는 소스코드
모듈 코드 모듈 내부에 존재하는 소스코드, 모듈 내부의 함수, 클래스 등의 내부코드는 포함 X
  • 구분하는 이유 : 소스코드의 타입에 따라 실행 컨텍스트를 생성하는 과정과 관리 내용이 다르기 때문

Untitled

1. 전역 코드

  • 전역 변수를 관리하기 위해 최상위 스코프인 전역 스코프를 생성
  • 호이스팅이 일어나는 var 키워드로 선언된 전역 변수와 함수 선언문으로 정의된 전역 함수는 전역 객체와 연결
  • 전역 코드가 평가되면 전역 실행 컨텍스트 생성

2. 함수 코드

  • 지역 스코프를 생성하고 지역 변수, 매개변수, arguments 객체 관리
  • 함수 코드가 평가되면 함수 실행 컨텍스트 생성

3. eval 코드

  • strict mode에서 자신만의 독자적인 스코프를 생성
  • eval 코드가 평가되면 eval 실행 컨텍스트가 생성

4. 모듈 코드

  • 모듈별로 독립적인 모듈 스코프를 생성
  • 모듈 코드가 평가되면 모듈 실행 컨텍스트가 생

23.2 소스코드의 평가와 실행

Untitled

  • 자바스크립트 엔진은 소스코드를 **“소스코드의 평가”**와 “소스코드의 실행” 2개의 과정으로 나누어 처리한다.
  • 소스코드 평가
    • 실행 컨텍스트를 생성
    • 변수, 함수 등의 선언문만 먼저 실행
    • 생성된 변수나 함수 식별자를 키로 실행 컨텍스트가 관리하는 스코프 등록
  • 소스코드 실행 (런타임)
    • 변수나 함수의 참조를 실행컨텍스트가 관리하는 스코프에서 검색해서 취득(실행에 필요한 정보를 취득)
    • 변수 값의 변경 등 소스 코드의 실행 결과는 다시 실행 컨텍스트가 관리하는 스코프에 등록
var x;
x = 1;
  • 소스코드 평가
    • var x를 먼저 실행
    • 생성된 변수 식별자 x는 실행 컨텍스트가 관리하는 스코프에 등록되고 undefined로 초기화
  • 소스코드 실행
    • var x는 소스코드 과정에서 이미 실행 완료된 상태
    • x 변수에 값을 할당하려면 먼저 x 변수가 선언된 변수인지 확인 과정 필요
    • 실행 컨텍스트가 관리하는 스코프에 x 변수가 등록되어 있는지 확인
    • x 변수가 선언된 변수라는 것이 확인이 되면 값을 할당하고 할당 결과를 실행 컨텍스트 등록 후 관리

23.3 실행 컨텍스트의 역할

// 전역 변수 선언
const x = 1;
const y = 2;

// 함수 정의
function foo(a) {
  // 지역 변수 선언
  const x = 10;
  const y = 20;

  // 메서드 호출
  console.log(a + x + y); // 130
}

// 함수 호출
foo(100);

// 메서드 호출
console.log(x + y); // 3
  1. 전역 코드 평가

    • 선언문만 먼저 실행 ex) const x, const y, function foo
    • 전역 스코프에 등록
  2. 전역 코드 실행

    • 전역 코드가 순차적으로 실행 ex) const x = 1, const y = 2, foo()
    • 함수가 호출되면 전역 코드의 실행을 일시 중단하고 코드 실행 순서를 변경하여 함수 내부로 진입
  3. 함수 코드 평가

    • 매개변수와 지역 변수 선언문이 먼저 실행 ex) const x, const y
    • 지역 스코프에 등록
    • arguments 객체가 생성되어 지역 스코프에 등록되고 this 바인딩도 결정
  4. 함수 코드 실행

    • 함수 코드 순차적 실행 ex) const x = 10; const y = 20; console.log()

    • console.log 메서드를 호출하기 위해 스코프체인을 통해 console을 검색

    • 검색하기 위해서는 전역 스코프와 지역 스코프가 연결되어야 함

    • 하지만 console은 스코프체인에 등록되어 있지 않음 → 전역 객체(window) 프로퍼티에 존재

      ⇒ 전역 객체의 프로퍼티가 전역 스코프를 통해 검색 가능해야 한다는 것을 의미

    • console.log 메서드의 실행이 종료되면 함수 호출 이전으로 되돌아가 전역 코드 실행을 계속 한다.

  5. 코드가 실행되려면,

    • 스코프를 구분하여 식별자와 바인딩된 값이 관리되어야한다.
    • 중첩 관계에 의해 스코프 체인을 형성하여 식별자를 검색할 수 있어야 한다.
    • 전역 객체의 프로퍼티도 전역 변수처럼 검색할 수 있어야 한다.
    • 현재 실행중인 코드의 실행 순서를 변경할 수 있어야하며 되돌아갈 수 았어야 한다.

❗ 이 모든 것을 관리하는 것이 바로 실행컨텍스트!

  • 식별자를 등록하고 관리하는 스코프와 코드 실행 순서 관리를 구현한 내부 메커니즘, 모든 코드는 실행 컨텍스트를 통해 실행되고 관리된다.**

23.4 실행 컨텍스트 스택

const x = 1;

function foo () {
  const y = 2;

  function bar () {
    const z = 3;
    console.log(x + y + z);
  }
  bar();
}

foo(); // 6

⭐ 자바스크립트 엔진은 먼저 전역 코드를 평가하여 전역 실행 컨텍스트를 생성

⭐ 함수가 호출되면 함수 코드를 평가하여 함수 실행 컨텍스트를 생성

→ 생성된 실행컨텍스트는 스택 자료구조(LIFO) 로 관리 ⇒ 실행 컨텍스트 스택

  1. 전역 코드의 평가와 실행
    • 전역 코드 평가 후 전역 실행 컨텍스트를 생성 → 실행 컨텍스트 스택에 푸시

  1. foo 함수 코드의 평가와 실행
    • 전역 코드의 실행은 일시중단, 코드의 제어권이 foo 함수 내부로 이동
    • 함수 코드를 평가하여 foo 함수 실행 컨텍스트 생성 → 실행 컨텍스트 스택에 푸시

  1. bar 함수 코드의 평가와 실행
    • 코드 제어권이 bar 함수 내부 이동
    • 함수 코드를 평가하여 bar 함수 실행 컨텍스트 생성 → 실행 컨텍스트 스택에 푸시

  1. foo 함수 코드로 복귀
    • bar 함수 종료되면 제어권은 다시 foo 함수로 이동
    • 자바스크립트 엔진은 bar 함수 실행 컨텍스트를 제거
    • 더 이상 실행할 코드가 없으므로 종료

  1. 전역 코드로 복귀
    • foo 함수 종료되면 제어권은 다시 전역코드로 이동
    • foo 함수 실행 컨텍스트를 제거
    • 더 이상 실행할 전역 코드가 남지 않으므로 전역 실행 컨텍스트 제거 , 실행 컨텍스트 스택에는 아무것도 남지 않음

실행 컨텍스트 스택은 코드의 실행 순서를 관리

  • 실행 컨텍스트의 스택의 최상위에 존재하는 실행 컨텍스트는 실행 중인 실행 컨텍스트라고 부른다.

23.5 렉시컬 환경

  • 렉시컬 환경 = 식별자와 식별자에 바인딩된 값, 그리고 상위 스코프에 대한 참조를 기록하는 자료구조로 실행 컨텍스트를 구성하는 컴포넌트
  • 실행 컨텍스트 스택 → 실행 순서 관리
  • 렉시컬 환경 → 스코프와 식별자 관리

  • 실행 컨텍스트는 LexicalEnvironment 컴포넌트VariableEnvironment 컴포넌트로 구성
  • 생성 초기에는 하나의 동일한 렉시컬 환경을 참조, 이후 몇가지 상황을 만나면 각자가 새로운 렉시컬 환경을 생성하여 내용이 달라지는 경우가 있다.
  • 렉시컬 환경은 EnvironmentRecord 컴포넌트OuterLexicalEnvironmentReference 컴포넌트로 구성
  • EnvironmentRecord 컴포넌트 (환경 레코드)
    • 스코프에 포함된 식별자를 등록하고 등록된 식별자에 바인딩된 값을 관리하는 저장소
  • OuterLexicalEnvironmentReference 컴포넌트 (외부 렉시컬 환경에 대한 참조)
    • 상위 스코프를 가리킨다.
    • 해당 실행 컨텍스트를 생성한 소스코드를 포함하는 상위 코드의 렉시컬 환경

23.6 실행 컨텍스트의 생성과 식별자 검색 과정

var x = 1;
const y = 2;

function foo (a) {
  var x = 3;
  const y = 4;

  function bar (b) {
    const z = 5;
    console.log(a + b + x + y + z);
}
  bar(10);
}

foo(20); // 42

23.6.1 전역 객체 생성

  • 전역 객체는 전역 코드가 평가되기 이전에 생성
  • 전역 객체도 Object.prototype을 상속 → 전역 객체도 프로토타입 체인의 일원

23.6.2 전역 코드 평가

  • 전역 코드 평가 순서
  1. 전역 실행 컨텍스트 생성
  2. 전역 렉시컬 환경 생성 2-1. 전역 환경 레코드 생성 2-1-1. 객체 환경 레코드 생성 2-1-2 선언적 환경 레코드 생성 2-2. this 바인딩 2-3. 외부 렉시컬 환경에 대한 참조 결정
  1. 전역 실행 컨텍스트 생성
  • 비어 있는 전역 실행 컨텍스트 생성 → 실행 컨텍스트 스택에 푸시
  1. 전역 렉시컬 환경 생성
  • 전역 렉시컬 환경을 생성 → 전역 실행 컨텍스트에 바인딩

2-1. 전역 환경 레코드 생성

  • var 키워드로 선언한 전역 변수와 let, const 키워드로 선언한 전역 변수를 구분하여 관리 필요함 → 전역 환경 레코드는 객체 환경 레코드선언적 환경 레코드로 구성
  • 객체 환경 레코드는 var키워드로 선언한 전역 변수와 함수 선언문으로 정의한 전역 함수 등을 관리
  • 선언적 환경 레코드는 let, const 키워드로 선언한 전역 변수 관리

2-1-1. 객체 환경 레코드 생성

  • 객체 환경 레코드는 BindingObject라고 부르는 객체와 연결된다.
  • 전역 코드 평가 과정에서 var 키워드로 선언한 전역 변수와 함수 선언문으로 정의된 전역 함수는 전역 객체의 프로퍼티와 메서드가 된다.
  • 이때 등록된 식별자를 전역 환경 레코드의 객체 환경 레코드에서 검색하면 전역 객체의 프로퍼티를 검색하여 반환 → 식별자(window)없이 프로퍼티를 참조할 수 있는 메커니즘 ex) window.alert X, alert O
var x = 1
function foo(a){}

2-1-2. 선언적 환경 레코드 생성

  • let, const 키워드로 선언한 전역 변수는 블록 스코프를 가진다.
  • const 키워드로 선언한 변수는 “선언 단계” 와 “초기화 단계”가 분리되어 진행 → 런타임에 실행 흐름이 변수 선언문에 도달하기 전까지 **일시적 사각지대(Temporal Dead Zone: TDZ)**에 빠짐
const y = 2;

2.2 this 바인딩

  • 전역 코드에서 this를 참조하면 전역 환경 레코드의 내부 슬롯에 바인딩되어 있는 객체가 반환된다. → window
  • 객체 환경 레코드와 선언적 환경 레코드에느 this 바인딩이 없다. → this 바인딩은 전역 환경 레코드와 함수 환경 레코드에만 존재

2.3 외부 렉시컬 환경에 대한 참조 결정

  • 외부 렉시컬 환경에 대한 참조는 상위 스코프를 말한다.
function foo (a) {
  var x = 3;
  const y = 4;

  function bar (b) {
    const z = 5;
    console.log(a + b + x + y + z);
}

23.6.3 전역 코드 실행

  • 전역 코드 평가가 끝난 후 전역 코드 실행 → 변수 x, y에 값이 할당되고 foo 함수 호출
  • 선언된 식별자인지 확인하고 어느 스코프의 식별자를 참조하면 되는지 결정이 필요 ⇒ 식별자 결정
  • 식별자 결정을 위해 식별자를 검색할 때는 실행 중인 실행 컨텍스트에서 식별자를 검색
  • 현재 실행중인 실행 컨텍스트는 전역 실행 컨텍스트이므로 전역 렉시컬 환경에서 식별자 x, y, foo를 검색한다.
  • 만약 식별자를 검색할 수 없으면 외부 렉시컬 환경으로 이동하여 검색 → 스코프 체인의 동작 원리
  • 하지만 전역 렉시컬 환경은 스코프 체인의 종점이므로 상위 스코프로올라갈 수 없어 식별자 검색에 실패하면 참조에러가 발생한다.

23.6.4 foo 함수 코드 평가

  • foo 함수가 호출되면 전역 코드의 실행을 일시 중단하고 foo 함수 내부로 코드 제어권이 이동 → 함수 코드 평가 시작
  • 함수 코드 평가 순서
  1. 함수 실행 컨텍스트 생성
  2. 함수 렉시컬 환경 생성 2.1 함수 환경 레코드 생성 2.2 this 바인딩 2.3 외부 렉시컬 환경에 대한 참조 결정
  1. 함수 실행 컨텍스트 생성

    • foo 함수 실행 컨텍스트 생성 → 실행 컨텍스트 스택에 푸시
    • 이때 foo 함수 실행 컨텍스트는 실행 컨텍스트 스택의 최상위, 실행 중인 실행 컨텍스트가 된다.
  2. 함수 렉시컬 환경 생성

    • foo 함수 렉시컬 환경을 생성
    • foo 함수 실행 컨텍스트 바인딩

2.1 함수 환경 레코드 생성

  • 함수 환경 레코드는 매개변수, arguments 객체, 함수 내부에서 선언한 지역 변수와 중첩함수를 등록하고 관리

2.2 this 바인딩

  • foo 함수는 일반 함수로 호출되었기 때문에 this 는 전역객체(window)를 가리킨다.

2.3 외부 렉시컬 환경에 대한 참조 결정

  • foo 함수 정의는 전역 코드 평가 시점에 평가, 이 시점의 실행 중인 실행 컨텍스트는 전역 실행 컨텍스트 → 외부 렉시컬 환경에 대한 참조에는 전역 렉시컬 환경의 참조가 할당
  • 자바스크립트는 함수를 어디서 호출했는지가 아니라 어디서 정의했는지에 따라 상위 스코프를 결정

23.6.5 foo 함수 코드 실행

  • foo함수가 순차적으로 실행 → x, y에 값이 할당되고 bar 함수 호출
  • 식별자 결정을 위해 실행 중인 실행 컨텍스트의 렉시컬 환경에서 식별자를 검색하기 시작
  • 모든 식별자가 현재 실행중인 실행 컨텍스트에서 검색할 수 있음 → 검색된 식별자에 값을 바인딩

23.6.6 bar 함수 코드 평가

  • bar함수 호출되면 bar 함수 내부로 코드의 제어권이 이동
  • 실행 컨텍스트와 렉시컬 환경의 생성과정은 foo 함수 코드 평가와 동일

23.6.7 bar 함수 코드 실행

  • bar 함수의 소스코드가 순차적으로 실행 → 매개변수에 인수가 할당, 지역 변수 z에 값 할당
  • 그 이후 console.log() 실행
  1. console 식별자 검색

    • console 식별자를 스코프 체인에서 검색
    • 현재 실행 중인 실행 컨텍스트의 렉시컬 환경에서 검색 시작하여 외부 렉시컬 환경에 대한 참조로 이어짐
  2. log 메서드 검색

    • console 객체의 프로토타입 체인을 통해 메서드 검색
  3. 표현식 a + b+ x+ y+ z 의 평가

    • 평가를 위해 식별자(a,b,x,y,z)를 검색
  4. console.log 메서드 호출

    • 표현식 a + b+ x+ y+ z가 평가되어 생성한 값을 console.log 메서드에 전달하여 호출

23.6.8 bar 함수 코드 실행 종료

  • 실행할 코드가 없으므로 bar 함수 코드의 실행이 종료 → bar 함수 실행 컨텍스트가 실행 컨텍스트 스택에서 제거 → foo 실행 컨텍스트가 실행 중인 실행 컨텍스트가 됨(최상위 스택)
  • bar 함수 실행 컨텍스트가 제거되었다고 해서 bar 함수 렉시컬 환경까지 즉시 소멸 X
  • 렉시컬 환경은 실행 컨텍스트에 의해 참조되기는 하지만 독립적인 객체
  • bar 함수 렉시컬 환경을 누군가 참조하고 있다면 bar 함수 렉시컬 환경은 소멸 X

23.6.9 foo 함수 코드 실행 종료

  • 실행 컨텍스트 스택에서 foo 함수 실행 컨텍스트가 제거 → 전역 실행 컨텍스트가 실행 중인 실행 컨텍스트가 된다(최상위 스택)

23.6.10 전역 코드 실행 종료

  • 전역 실행 컨텍스트도 실행 컨텍스트에서 제거 → 실행 컨텍스트 스택에는 아무것도 없음

23.7 실행 컨텍스트와 블록 레벨 스코프

  • var 키워드로 선언한 변수는 함수의 코드 블록만 지역 스코프로 인정 → 함수 레벨 스코프
  • let, const 키워드로 선언한 변수는 모든 코드 블록을 지역 스코프로 인정 → 블록 레벨 스코프
let x = 1;

if (true) {
  let x = 10;
  console.log(x); // 10
}

console.log(x); // 1
  • let 변수 선언 → if 문의 코드 블록을 위한 블록 레벨 스코프 생성
  • 선언적 환경 레코드를 갖는 렉시컬 환경을 새롭게 생성 → 기존의 전역 렉시컬 환경을 교체
  • 외부 렉시컬 환경에 대한 참조는 if 문이 실행되기 이전의 전역 렉시컬 환경을 가르킴
  • 코드 블록이 실행될 때마다 독립적인 렉시컬 환경을 생성하여 식별자의 값을 유지 → 클로저