Jiyong's STUDY

Javascript의 실행 컨텍스트 본문

Web/자바스크립트

Javascript의 실행 컨텍스트

Kingjiyong 2021. 5. 26. 17:46

https://velog.io/@woobuntu/실행-컨텍스트렉시컬-환경과-this

 

실행 컨텍스트(렉시컬 환경과 this)

ES3의 '중첩 스코프'와 비교하여 ES5의 '렉시컬 환경'개념에 대해 알아보고, 나아가 this바인딩에 대해서도 살펴본다.

velog.io

해당 글은 위 링크를 보고 공부하고 이해한 내용을 정리한 글입니다.

그리고 해당 글의 예제들이 ES 문법으로 작성되지는 않았지만 해당 글에서는 ES6+ 문법에서의 컨텍스트도 다루겠습니다.

틀린 부분이 많을 수 있으니 지적해주시면 감사하겠습니다.

실행 컨텍스트: {
  렉시컬 환경 컴포넌트: {
    렉시컬 환경: {
      환경 레코드: {
        선언적 환경 레코드: { // 글로벌 스코프에서는 오브젝트 환경 레코드
          // 현재 스코프에 선언된 변수와 함수들이 식별되어 있음
        }
      },
      외부 렉시컬 환경 참조 : 상위 스코프 참조
      // 글로벌 스코프에서는 상위 스코프가 없으므로 null 참조
    },
  },
  변수 환경 컴포넌트: {
    // 렉시컬 환경 컴포넌트에 설정된 '렉시컬 환경'을 복사한 것으로 렉시컬 환경 컴포넌트와 초기값이 같다.
    // 실행 단계에서 참조하는 것은 렉시컬 환경 컴포넌트이고, 변수 환경 컴포넌트는 이후 초기값으로의 환원을 위한 컴포넌트이다.
    // 함수가 호출될 때마다 매번 새로운 실행 컨텍스트를 생성하는 걸로 알고 있는데 캐시 개념이라도 적용되는 걸까... x같은 자스...
  },
  this바인딩 컴포넌트
  // 글로벌 스코프에서는 Global object참조
}

실행 컨텍스트의 형태라고 한다.

 

"ES5에서는 찾는 변수가 '환경 레코드'에 없으면 외부 렉시컬 환경 참조를 통해 중첩 스코프를 타고 올라간다는 것을, 객체의 property참조 형태로 보다 가시화해서 보여준다."

 

그리고 '컴포넌트' 라는 용어는 자바스크립트 스펙상의 용어는 아니라고 한다.

단 렉시컬 환경에서, 컴포넌트라는 용어를 빼면 같은 이름의 계층이 두 개가 존재하기 때문에

혼동을 방지하기 위하여 사용된 것이라고 서술되어 있다.

 

 

그리고 이해해야 할 몇 개의 전제가 있다고 하는데,

 

1. 실행 컨텍스트는 함수의 호출로 생성된다.

2. 컴파일의 단위도 함수 코드이다.

3. 호출된 함수들의 관계는 콜스택이라는 자료구조로 표현된다.

 

3번은 알고 있었는데 1번과 2번은 잘 모르고 있었다.

 

컴파일의 단위도 함수 코드이고 실행 컨텍스트도 함수 단위로 생성된다고 볼 수 있다.

정말 자바스크립트를 이해하기 위해서는 함수 관련으로 공부를 많이 해야 하는 것 같다.

Call Stack은 다음과 같다.

debugger;는 해당 위치에서 프로그램이 멈추는데,

여러 곳에 두면 BP를 찍고 디버깅을 하는 것과 같다.

 

아무튼, BP가 코드가 최상위에 존재하는데 Call Stack에 (anonymous)라는게 존재한다.

익명 함수가 호출되어 있다는 것을 알 수 있다.

 

자바스크립트는 글로벌 스코프의 코드도 함수의 코드로 보기 때문에, 전체 코드가 함수에 묶였다고 보면 된다.

그리고 자바스크립트 프로그램은 렌더링이 끝나고 나면, 글로벌 스코프에 있는 코드를 함수의 코드로 간주하여 실행하기 때문이기도 하다고 한다.

 

woobuntu님은 해당 코드를 이와 같이 비유했다.

(function() {
  debugger;

  var a0 = "jiyong";

  function a1() {
    debugger;
    var a2 = 3;
    function a3() {
      debugger;
      console.log(a0, a2);
    }
    a3();
    debugger;
  }

  a1();
  debugger;
})();

전체 코드가 익명 함수 안에서 즉시실행 되는 것이라고 이해하면 편하다.

 

// 글로벌 스코프에 해당하는 실행 컨텍스트
실행 컨텍스트: {
  렉시컬 환경 컴포넌트: {
    렉시컬 환경: {
      환경 레코드: {
        오브젝트 환경 레코드: {
          a0: undefined,
          a1: f a1(),
          // 기타 글로벌 스코프에 존재하는 모든 변수 및 함수들
        }
      },
      외부 렉시컬 환경 참조 : null
    },
  },
  this바인딩 컴포넌트: Global object참조
}

글로벌 스코프에는 a0이라는 변수와 a1이라는 함수가 선언되어있다.

그렇기에 a0과 a1은 스코프에 엮여있다.

 

그리고 a0이 undefined인 이유는 a0이 선언은 되었지만 아직 3번줄이 실행이 안되었기 때문이다.

외부 렉시컬 환경 참조는 지금이 글로벌 스코프기 때문에 null.

 

다음 BP다.

 

콜스택을 확인하면 익명 함수 위에 a1이 들어갔다.

스택이므로 FILO 구조로 a1이 위에 쌓이고 나가게 될 것이다.

즉 (anonymous)는 마지막에 나가게 될 것이다.

 

그리고 함수 a1에 진입했기 때문에 컨텍스트가 변경되었다.

이제 a1의 컨텍스트를 보면

// a1함수 스코프에 해당하는 실행 컨텍스트
실행 컨텍스트: {
  렉시컬 환경 컴포넌트: {
    렉시컬 환경: {
      환경 레코드: {
        선언적 환경 레코드: {
          a2: undefined,
          a3: f a3(),
        }
      },
      외부 렉시컬 환경 참조 : a1함수의 [[Scope]] 참조
    },
  },
  this바인딩 컴포넌트: Global object
}

local에 있는 두 가지, a2와 a3.

a2는 a1 내부에 존재하는 지역 변수고 a3은 함수이다.

이 변수와 함수는 선언적 환경 레코드가 참조한다.

(글로벌 스코프의 실행 컨텍스트가 아닌 실행 컨텍스트는 모두 선언적 환경 레코드라고 한다.)

 

그리고 외부 렉시컬 환경은 a1 함수의 스코프를 참조한다고 되어있는데,

a1 함수의 스코프는 Global 스코프다. (정확히는 Global 스코프의 오브젝트 환경 스코프)

-> 외부 렉시컬 환경에서 외부 렉시컬 환경으로 들어갈 수 없다.

그리고 a3의 스코프를 확인하면 Closure로 표기되어 있다.

(렉시컬 스코프와 Closure는 동일한 개념으로 볼 수 있다고 한다.)

 

다음 BP다.

 

콜스택을 보면 a1 위에 a3이 올라와있다.

그 이유는 a3 안에 진입했기 때문이다. 그리고 a3은 a1 안에 있으니 이런 식으로 콜스택이 쌓일 수 밖에 없는 것.

 

a3의 컨텍스트는 다음과 같다.

// a3함수 스코프에 해당하는 실행 컨텍스트
실행 컨텍스트: {
  렉시컬 환경 컴포넌트: {
    렉시컬 환경: {
      환경 레코드: {
        선언적 환경 레코드: {
          // 선언된 변수나 함수가 없다
        }
      },
      외부 렉시컬 환경 참조 : a3함수의 [[Scope]] 참조
    },
  },
  this바인딩 컴포넌트: Global object
}

 

그리고 스코프를 확인하면 지역에는 선언된 것이 없으므로 변수나 함수는 존재하지 않는다.

즉 선언적 환경 레코드가 비어있게 된다.

 

하지만 a3은 a0과 a2를 참조하는데, 어디서 참조할까?

외부 렉시컬 환경 참조를 참조한다.

 

그리고 외부 렉시컬 환경은 a3 함수의 스코프를 참조하는 것으로 되어있는데,

 

a2는 Closure(a1)에서 참조해왔고, a0은 Global에서 참조해왔다.

'Web > 자바스크립트' 카테고리의 다른 글

Javascript의 call, apply, bind  (0) 2021.06.29
Javascript의 this와 call  (0) 2021.06.28
Javascript의 Hoisting과 Scope  (0) 2021.06.28
클로저(Closure)란?  (0) 2021.06.24
Javascript의 함수  (0) 2021.05.26