실행 컨텍스트란?
실행 컨텍스트는 스코프, 호이스팅, this, 클로져 등의 동작원리를 담고 있는 자바스크립트의 핵심원리이다. 이는 실행 가능한 코드를 형상화하고 구분하는 추상적인 개념, 즉 실행 가능한 코드가 실행되기 위해 필요한 환경이라고 할 수 있다. 실행 가능한 코드란 전역 코드와 함수 코드를 말한다. 자바스크립트가 실행될 때 우선적으로 전역 실행 컨텍스트가 만들어지며 함수가 실행될 때 함수 실행 컨텍스트가 만들어져 쌓인다.
자바스크립트 엔진이 코드를 실행하기 위해 필요한 정보는 변수 / 함수 선언 / 스코프 / this가 있다.
let x = 'global x';
let y = 'global y';
function outer() {
let z = 'local z';
console.log('outer 영역');
function inner() {
let x = 'local x';
console.log('inner 영역');
console.log(x);
console.log(y);
console.log(z);
}
inner();
}
outer();
//output
outer 영역
inner 영역
local x
global y
local z
위의 함수를 실행하면 아래 그림과 같은 실행 컨텍스트 스택(좌)이 쌓이고 각 스택마다 실행에 필요한 정보들을 담은 객체(우)를 생성한다. 스코프는 모든 식별자(변수, 상수, 함수)에 대한 유효 범위이다. 그중 렉시컬 스코프란 함수를 어디에 선언하였는지에 따라 결정되는 스코프를 의미한다.
그림처럼 스코프가 중첩된 것을 스코프 체인이라고 한다. inner 함수 안에 y와 z가 없음에도 inner 함수 안에서 출력할 수 있었던 것은 이 스코프 체인을 따라 상위 스코프로 올라가 변수를 탐색했기 때문이다.
클로저
자바스크립트에서 함수는 일급 객체이다. 일급 객체란, 다른 변수처럼 대상을 다룰 수 있는 것을 말한다. 자바스크립트에서 함수를 변수처럼 다룰 수 있다는 말이다.
클로저는 함수의 일급 객체 성질을 이용한 것으로 내부 함수가 자신이 선언되었을 때의 환경인 스코프를 기억하여 스코프 밖에서 호출되어도 기억한 스코프에 접근할 수 있는 것을 의미한다. (변수의 경우에도 마찬가지이다. 함수가 생성될 때, 함수 내부에서 사용되는 변수들이 외부에서 호출될 때 이미 생성된 함수의 스코프에 저장되었으므로 함수 외부에서 함수 내부에 접근하게 되는 것이다. 이렇게 함수와 함수가 사용하는 변수들을 저장한 공간을 클로저라고 한다.)
let rate = 1.05;
function app() {
let base = 10;
return function (price) {
return price * rate + base;
};
}
const getPrice = app();
getPrice(120) //output: 136
app()(1) //output: 11.05
rate = 1.1;
app()(1) //output: 11.1
- base는 app 함수 내부, rate는 app 함수 외부 스코프에 존재한다.
- 함수가 참조하는 변수는 실행 시점에 실행 컨텍스트에 의해 스코프가 결정된다.
- rate를 변경하면 두 클로저 함수 호출에 반영되지만, base는 증가해도 영향을 미치지 않는다.
- base는 app 호출 시 매번 생성되는 반면, rate는 매번 생성되지 않는다.
function makeCounter() {
let count = 0;
function increase() {
count++;
console.log(count);
}
return increase;
}
const increase = makeCounter();
console.log(count) //Error: count is not defined
increase(); //output: 1
increase(); //output: 2
increase(); //output: 3
클로저를 왜 사용하는지에 대한 이유는 위의 코드를 보면 알 수 있다. count에 직접 접근하지는 못하지만 increase 함수를 통해 접근하는 것은 가능하다. 이 특징을 살려 클로저가 갖는 장점은 다음과 같다.
- 상태 유지: 현재 상태를 기억하고 변경된 최신 상태를 유지
- 전역 변수 사용 억제: 가변 데이터를 피하고 오류를 최소화
- 정보 은닉: 클래스의 private을 흉내
'[JavaScript]' 카테고리의 다른 글
[javascript] 동기vs비동기 (0) | 2022.10.10 |
---|---|
[javascript] 호이스팅(hoisting)과 일시적 사각 지대(TDZ) + var, let, const (0) | 2022.10.05 |
[javascript] prototype과 __proto__ (0) | 2022.10.03 |
[javascript] 생성자 함수와 클래스 (0) | 2022.10.03 |
[javascript] this + bind, call, apply (0) | 2022.10.02 |
댓글