티스토리 뷰
실행 컨텍스트(Execution context)
Javascript 코드블록이 실행되는 환경(무대)를 말한다. 코드 실행에 필요한 다양한 정보(변수, scope chain, this 등)를 담고 있으며 전역 코드, eval(), 함수를 실행하는 세가지 경우에 의해 생성된다. 실행 컨텍스트는 stack으로 쌓인다.
Global execution context
코드가 실행되기 전에 생성되며 함수 내부에 존재하지 않는 모든 코드는 여기에 존재한다. 글로벌 실행 컨텍스트는 단 하나만 존재하며 js engine이 어떤 코드를 실행하는 모든 기간 동안 존재한다.
Functional execution context
Global execution context가 생성된 이후 함수가 실행될 때마다 생성되고, 함수가 종료되면 stack에서 삭제(pop)된다.
활성객체 생성
JS engine은 실행 컨텍스트가 생성되면 해당 컨텍스트에서 실행에 필요한 여러 정보를 담을 객체를 생성하는데 이것이 활성객체이다. 활성객체는 변수 객체(매개변수, 지역변수), scope chain, this의 정보를 갖는다.
Scope chain
scope란 해당 함수(or 전역)의 실행 컨텍스트에서 참조할 수 있는 유효한 범위를 말하며 js는 함수레벨에서 lexical scope를 갖는다. 좀 더 자세히 설명하자면, 실행 컨텍스트 안에서 어떤 변수에 접근할 때 scope chain이라는 변수객체의 list를 차례대로 훑으며 저장된 값을 찾는다. 이 때 scope chain는 아래와 같이 생성된다.
- 함수의 [[scopes]]: 함수가 생성(선언) 될 때, 실행 중인 context의 scopde chain이 할당된다. (함수의 실행 이전에 할당)
- Scope chain: 실행 컨텍스트가 생성될 때, 컨텍스트를 생성시킨 함수의 변수객체와 [[scopes]] property를 연결한 list
Ex 1)
var var1 = 1;
var var2 = 2;
function func() {
var var1 = 10;
var var2 = 20;
console.log(var1); // 10
console.log(var2); // 20
}
func();
console.log(var1); // 1
console.log(var2); // 2
맨 처음 script가 실행될 때 전역 context의 scope chain은 전역 변수 객체 gloval VO = {var1: 1, var2: 2}가 된다.
func()이 선언될 때 scope chain에는 global 변수객체만 존재하기 때문에(global context는 [[scopes]]가 없기 때문)
func.[[scopes]]는 [global VO]가 된다.
func()이 호출될 때 func context의 scope chain은 func의 변수 객체와 [[scopes]]를 합친 [func VO, gloval VO]가 된다.
Ex 2)
var value = "value1";
function printValue() {
return value;
}
function printFunc(func) {
var value = "value2";
console.log(value); // "value2"
console.log(func()); // "value1"
}
printFunc(printValue);
맨 처음 script가 실행될 때 전역 context의 scope chain은 전역 변수 객체 gloval VO = {value="value1"}가 된다.
printValue()가 선언될 때 scope chain에는 global 변수객체만 존재하기 때문에 printValue.[[scopes]]는 [global VO]가 된다.
printFunc()이 선언될 때 scope chain에는 global 변수객체만 존재하기 때문에 printFunc.[[scopes]]는 [global VO]가 된다.
printFunc()이 호출될 때 printFunc context의 scope chain은 printFunc의 변수객체 printFunc VO = {value: "value2"}와 [[scopes]]를 합친 [printFunc VO, gloval VO]가 된다. 즉 value는 printFunc VO에서 찾은 "value2"가 된다.
printValue()가 호출될 때 printValuecontext의 scope chain은 printValue의 변수객체 printValueVO = {}와 [[scopes]]를 합친 [printValue VO, gloval VO]가 된다. 즉 value는 gloval VO에서 찾은 "value1"가 된다.
Ex 3)
var x = 10;
var outer = function(){
var y = 20;
var inner = function(){
var z = 30;
console.log(x + y + z); // 60
};
};
맨 처음 script가 실행될 때 전역 context의 scope chain은 전역 변수 객체 gloval VO = {x=10}가 된다.
outer()가 선언될 때 scope chain에는 global 변수객체만 존재하기 때문에 outer.[[scopes]]는 [global VO]가 된다.
outer()이 호출될 때 outer context의 scope chain은 outer의 변수객체 outer VO = {y: 20}와 [[scopes]]를 합친 [outer VO, gloval VO]가 된다. inner()가 선언되면서 inner.[[scopes]]가 설정되는데 현재 outer context의 scope chain인 [outer VO, gloval VO]가 할당된다.
inner()가 호출될 때 inner context의 scope chain은 inner의 변수객체 inner VO = {z: 30}와 [[scopes]]를 합친 [inner VO, outter VO, gloval VO]가 된다. 따라서 scope chain에 따라 z는 global VO에서, y는 outer VO에서, z는 inner VO에서 값을 찾게 된다.
'JavaScript' 카테고리의 다른 글
Regular function vs arrow function (0) | 2022.08.01 |
---|---|
var, let, const (0) | 2022.08.01 |
keys, getOwnPropertyNames, for...in (0) | 2022.08.01 |
this binding (0) | 2021.11.09 |
Closure (0) | 2021.11.09 |