javascript

[CoreJavascript] 2과 실행컨텍스트

프로일기꾼 2025. 1. 28. 14:33

Execution Context

    • = 코드를 실행하는데 필요한 주변 환경
    • = 코드의 배경이 되는 조건/환경
    • = 코드를 실행하는 데에 필요한 배경이되는 환경
    • = 함수를 실행할 때 필요한 환경정보를 담은 객체

 

  • javascript에서 동일한 조건을 지닐 수 있는 환경은 4가지(전역공간, 함수, eval, module) 밖에 없다.
    • eval은 여러 문제를 야기하는 몹시 위험한 명령
  • 자바스크립트 코드가 실행되는 순간에 바로 전역 컨텍스트가 생성되고, 전체 코드가 끝날 때에 비로소 전역 컨텍스트가 종료되기에 '전역공간'은 거대한 함수 공간이라고 볼 수 있다.
  • module도 import 되는 순간에 그 모듈 내부에 있는 컨텍스트가 생성이 되고 그 모듈 코드가 전부 끝났을 때 컨테스트 종료되기에 module 또한 하나의 함수 공간이라고 간주할 수 있다.
  • 결국 자바스크립트의 독립된 코드 뭉치라고 할 수 있는 것은 곧 '함수'라고 볼 수 있다.
  • 전역공간, 함수, 모듈로 묶인 내부에서는 "같은 환경 안에 있다"라는게 성립한다.
  • js는 함수에 의해서만 컨텍스트를 구분할 수 있다.(if, for, switch 같은 블록 레벨에서는 컨텍스트 생성 X)

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

 

  • 위 코드에서 먼저 실행되는 순서와 결과를 예측할 수 있다면 실행 컨텍스트의 절반을 아는 것이다.
  • 1, 2, 3, 4 번 순서로 실행이 된다.
  • JS에서는 함수의 실행을 스택에 담아 관리하고 있는데, 코드 실행에 관여하는 스택을 "콜스택"이라고 한다.
    • 콜스택: 현재 어떤 함수가 동작중인지, 다음에 어떤 함수가 호출될 예정인지 등을 제어하는 자료구조
  • 위 코드의 결과값을 생각해보자.
    • 결과값은 1 undefined 1 1 으로 출력된다.

 

실행 컨텍스트 내부 구성

  1. variable environment: 최초의 식별자 정보(변화 반영X)
  2. lexical environment: 실행 컨텍스트의 내용에 따라 변수의 값이 변경될 때 '변경사항을 계속 트래킹'하는 정보(변화 반영O)
    • environmentRecord: 현재 문맥의 식별자 수집(hoisting)
    • outerEnvironmentReference: 외부 식별자 참조(scope chain)
  3. this binding

 

lexical environment

- 사전 뜻: 어휘적/사전적 환경
- = 어떤 실행 컨텍스트 A에 대한 환경정보가 담겨 있는 사전.
- = 실행 컨텍스트를 구성하는 환경 정보들을 모아 사전처럼 구성한 객체
- lexical environment는 environment record와 outer environment reference로 구성되어 있다.

{
  내부식별자 a: 현재값은 undefined이다.
  외부 정보: D를 참조한다.
}
  • environmentRecord: 현재 문맥의 식별자 정보가 수집된다. 실행 컨텍스트가 최초 실행될 때 제일 먼저 수행하는 일이 바로 이것이다.
  • 현재 컨텍스트의 식별자 정보들을 수집해서 environmentRecord에 담는 과정을 "호이스팅"이라고 한다. 호이스팅은 실제하는 현상이 아니고, environmentRecord의 정보 수집 과정을 좀 더 쉽게 이해하기 위해서 만든 허구의 개념일 뿐이다.

 

호이스팅

  • 끌어올린다'는 의미를 담고 있는 단어인데, 식별자 정보를 실행 컨텍스트의 맨 위로 끌어올린다는 것을 뜻한다.
console.log(a());
console.log(b());
console.log(c());

// 함수 선언문 같은 경우에는 다른 식별자와 다르게 함수 선언문 전체를 실행컨텍스트 맨 위로 끌어올린다.
function a() {
  return 'a';
}


var b = function bb() {
  return 'bb';
}


var c = function() {
  return 'c';
}
  • 위의 코드는 호이스팅이 되면 아래와 같은 상황이 된다.

 

/ **
(호이스팅)
위로 끌어올려진 내용,
바로 이 부분 전체가 environmentRecord 이다.
fucntion a() {
  return a;
}
var b;
var c;

*/
console.log(a());
console.log(b());
console.log(c());

b = function bb() {
  return 'bb';
}

c = function() {
  return 'c';
}

 

  • environmentRecord에 담긴 정보는 아래와 같다.
{
  function a() { ... }
  b: undefined,
  c: undefined
}

 

  • environmentRecord에 담기는 내용은 실제로 일어나는 일이지만, (호이스팅)이라고 작성한 코드 부분은 사람이 이해하기 쉽게 만들어 놓은 허구의 개념일 뿐이다.

 

outerEnvironmentReference

  • = 외부 lexical environment에 대한 참조를 뜻한다.
  • = 현재 문맥과 관련이 있는 외부 식별자 정보를 참조한다.

  

 

  • outerEnvironmentReference가 관여하는게 바로 'scope chain'이다. 다시 말해, outerEnvironmentReference에 의해서 만들어지는 것이 'scope chain'이다.
  • 스코프란 변수의 유효범위를 말한다. 변수의 유효 범위는 실행컨텍스트가 만드는 것. 같은 말로 변수의 유효 범위는 실행 컨텍스트에 의해 결정되는 것이다.



  • 그렇다면 스코프 체인이란 어떤 특성이 있는가?
  • (위 그림 참조) outer에서 선언한 변수는 inner 실행 컨텍스트 안에 outerEnvironmentReference에 의해 접근될 수 있다. 마찬가지로 전역 컨텍스트에서 선언한 변수도 outer 컨텍스트의 outerEnvironmentReference로 접근 가능하다.
  • 하지만 반대로는 가능하지 않다. inner에서 선언한 변수는 outer에서 접근할 수 없다. outer에서는 inner의 LexicalEnvironment에 대해 접근할 수 있는 수단이 없기 때문.( = inner 컨텍스트를 참조하고 있는 대상이 없기 때문)
  • 위와 같은 특성이 바로 '스코프'이다. 외부로는 나갈 수 있는데, 자기보다 더 안쪽으로는 들어갈 수 없다. (곧 변수의 유효 범위를 의미)
  • (결론) => scope chain: inner 컨텍스트 내에서 변수를 찾으라고 하면 가장 가까운 inner 컨텍스트 내 environmentRecord에 변수가 있는지 찾고, 만약 inner에 없으면 다음 외부 컨텍스트에 접근해 변수를 찾고 없으면 다시 외부 컨텍스트에서 찾는 것. 가장 가까운 자기 자신 부터 점점 멀리 있는 스코프로 찾아 나가는 것.
  • 가장 먼저 찾아진 것만(외부 컨텍스트 정의되어 있더하더라도) 접근할 수 있다는 것 'shadowing'(가린다는 개념)이라고도 한다.