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` 는 암묵적 전역 변수 생성이 허용되지 않는다.