Skip to main content

DeepDive JS실행스코프

실행 컨텍스트

실행 컨텍스트 ( EC ) : JavaScript 코드가 실행되는 환경으로 정의

  • 3가지로 구성된다. = Variable object + scope chain + this
  • 함수가 실행될때마다 실행 컨텍스트는 스택으로 쌓이게된다.
  • *this는 함수를 실행한 주체가 된다. 실행컨텍스트와 다르게 자유롭게 바인딩이 가능하다.

자바스크립트에서 실행 컨텍스트는 세 가지 유형으로 나뉩니다:

1.전역 실행 컨텍스트(Global Execution Context, GEC):

  • 이는 자바스크립트 코드가 처음 브라우저에 로드될 때 실행되는 기본 실행 컨텍스트.
  • 전역 실행 컨텍스트는 하나만 존재 (단일 스레드이기 때문)

2.함수 실행 컨텍스트(Functional Execution Context, FEC):

  • 함수 실행 컨텍스트는 자바스크립트 엔진이 함수 호출을 발견할 때마다 생성되는 컨텍스트
  • 함수 실행 컨텍스트는 전역 실행 컨텍스트의 모든 코드에 접근할 수 있지만, 그 반대는 불가능
  • 브라우저에서 코드가 strict 모드에서 실행될 경우, 함수 실행 컨텍스트에서 this 값은 undefined가 되며, 그렇지 않으면 window 객체가 됩니다.

3.Eval: eval 함수 내에서 생성되는 실행 컨텍스트입니다.

실행 컨텍스트 스택(Execution Context Stack, ECS)

  • 스택 데이터 구조로, 자바스크립트 코드의 실행 동안 생성된 모든 실행 컨텍스트를 저장하는 구조입니다.

  • 이 스택은 LIFO(Last In, First Out) 방식으로 작동

  • 전역 실행 컨텍스트는 기본적으로 실행 컨텍스트 스택에 포함되어 있으며, 스택의 맨 아래에 위치.

  • 함수 호출을 발견하면 해당 함수에 대한 함수 실행 컨텍스트를 생성 후 스택의 맨 위에 추가

  • 함수의 모든 코드가 실행되면, 실행 컨텍스트를 스택에서 제거하고, 그 아래에 있는 함수의 실행 컨텍스트를 실행

자바스크립트 엔진은 실행 컨텍스트를 두 가지 단계에서 생성합니다:

1.생성 단계 (Creation Phase)

  • 생성 단계는 자바스크립트 엔진이 함수를 호출했지만 아직 실행 안함.
  • 컴파일을 하면서 코드를 스캔한다.
  • 이 단계 때문에 호이스팅이 일어난다.

1.1.변수 객체(Variable Object) 생성

  • 활성화 객체는 자바스크립트에서 특별한 객체
  • 함수 스코프 안의 모든 변수, 함수 인수, 내부 함수 선언 정보를 포함.
  • 실행 단계에서는 활성화 객체(Activation Object)로 된다.
  • 규칙
    • 1.선언만 변수 객체에 등록된다.
    • 1.1 var a=1 의 경우 a:undefined 등록
    • 1.2 a=1의 경우 무시
    • 1.3 function funA(){} 의 경우 등록
    • 1.4 func = function(){} 의 경우 무시
    • 1.5 FEC의 경우 함수 argumentObj에 변수,값 모두 등록

1.2.스코프 체인(Scope Chain) 생성

  • 현재 함수의 변수 객체를 포함하여, 현재 함수가 속한 모든 변수 객체의 목록이다.
  • 끝에는 전역 실행 컨텍스트의 변수 객체가 있다.

1.3.this 값 결정: 스코프 체인이 생성된 후, 자바스크립트 엔진은 this의 값을 초기화합니다.

2.실행 단계 (Execution Phase)

2.1 할당이 이루어 진다.

  • 선언이 없는 경우 a = 3 선언 및 할당이 동시에 일어난다.
  • 함수가 호출되면 새로운 EC를 만든다.

변수 객체

function funA (a, b) {
var c = 3;
var d = 2;
d = function() {
return a - b;
}
}
funA(3, 2);

--- #1.CreationPhase : funA EC of VariableObject
variableObject = {
argumentObject : {
0: a,
1: b,
length: 2
},
a: 3,
b: 2
c: undefined
}
---#2.Execution Phase
variableObject = {
argumentObject : {
0: a,
1: b,
length: 2
},
a: 3,
b: 2,
c: 3,
d: pointer to the function defintion of d
}

실행컨텍스트

b = 4 // 호이스팅  
a = 1;
var b = 2;
cFunc = function(e) {
var c = 10;
var d = 15;
a = 3
function dFunc() {
var f = 5;
}
dFunc();
}
cFunc(10);
---생성
globalExecutionContextObj = {
activationbj: {
argumentObj : {
length:0
},
//a는 선언이 없어 등록되지 않는다.
b: undefined,
},
scopeChain: [GLobal execution context variable object],
this: value of this
}
---실행
globalExecutionContextObj = {
activationbj: {
argumentObj : {
length:0
},
b: 4,
cFunc: Pointer to the function definition,
a: 1
},
scopeChain: [GLobal execution context variable object],
this: value of this
}
---
cFuncExecutionContextObj = {
activationbj: {
argumentObj : {
0: e,
length:1
},
e: 10,
c: undefined,
d: undefined
dFunc: Pointer to the function definition,
},
scopeChain: [cFunc variable object, Global exection context variable object],
this: value of this
}
---
cFuncExecutionContextObj = {
activationbj: {
argumentObj : {
0: e,
length:1
},
e: 10,
c: 10,
d: 15
// a는 활성화 객체에 없으니 스코프체인을 타고 올라간다.
dFunc: Pointer to the function definition, // 힙메모리 위치를 가르킴
},
scopeChain: [cFunc variable object, Global exection context variable object],
this: value of this
}

스코프체인

var a = 1;

function cFunc(e) {
var c = 10;
var d = 15;
f = 99999 // 암묵적 전역(implicit global)> 전역 객체에 생성&할당

function dFunc() {
var f = 5;
console.log(f); // Logs 5
console.log(c); // Logs 10
console.log(a); // Logs 1
}
dFunc();
}
cFunc(2);

cFunc의 스코프 체인: [cFunc 변수 객체, 전역 실행 컨텍스트 변수 객체]
dFunc의 스코프 체인: [dFunc 변수 객체, cFunc 변수 객체, 전역 실행 컨텍스트 변수 객체]
*암묵적 전역 방지 : `strict mode` 는 암묵적 전역 변수 생성이 허용되지 않는다.