예를 들어, js 콜 스택의 최대 용량을 넘기면 에러를 던진다
var eternalLoop = function() {
return eternalLoop();
}
// Uncaught RangeError; Maximum call stack size exceeded
실행 컨텍스트와 콜 스택 예시:
// ------------------------------ (1)
var a = 1;
function outer() {
function inner() {
console.log(a); // undefined
var a = 3;
}
inner(); // ------------------- (2)
console.log(a); // 1
}
outer(); // -------------------- (3)
console.log(a); // 1
위 코드에 대한 설명은 아래와 같다.
- (1) 자바스크립트 코드를 실행하는 순간 전역 컨텍스트가 콜 스택에 담긴다.
- (3) outer 함수를 호출하면 자바스크립트 엔진은 outer에 대한 환경 정보를 수집해서 outer 실행 컨텍스트를 생성한 후 콜 스택에 담는다. (콜 스택 맨 위에 outer 실행 컨텍스트가 놓인 상태가 됐으므로, 전역 컨텍스트와 관련된 코드의 실행을 일시 중단하고 대신 outer 실행 컨텍스트와 관련된 코드, 즉 outer 함수 내부의 코드들을 순차적으로 실행한다.)
- (2) inner 함수의 실행 컨텍스트가 콜 스택의 가장 위에 담기면 outer 컨텍스트와 관련된 코드의 실행을 중단하고 inner 함수 내부의 코드를 순서대로 진행한다.
- inner 함수 실행 종료되면 콜 스택에서 제거됨
- 아래에 있던 outer 컨텍스트가 콜 스택 맨 위에 존재하게 되므로, (2)의 다음줄부터 이어서 실행
- a 변수 출력하면 outer 실행 컨텍스트가 콜 스택에서 제거되고, 전역 컨텍스트만 남게됨
- 실행을 중단했던 (3) 다음줄 이어서 실행
- a 변수 값 출력하면 전역 공간에 실행할 코드가 없어 전역 컨텍스트도 제거. 콜 스택 비어진 채로 종료
실행 컨텍스트가 활성화 될 때 자바스크립트 엔진은 해당 컨텍스트에 관련된 코드들을 실행하는데 필요한 환경 정보들을 수집해서 실행 컨텍스트 객체에 저장함.
environmentRecord와 호이스팅
호이스팅 규칙
function a (x) {
console.log(x); //------------ (1)
var x;
console.log(x); //------------ (2)
var x = 2;
console.log(x); //------------ (3)
}
a(1)
충격의 결과:
왜 그럴까?
function a (x) {
var x; // 수집 대상 1의 변수 선언 부분
var x; // 수집 대상 2의 변수 선언 부분
var x; // 수집 대상 3의 변수 선언 부분
x = 1; // 수집 대상 1의 할당 부분
console.log(x); //------------ (1)
console.log(x); //------------ (2)
x = 2; // 수집 대상 2의 할당 부분
console.log(x); //------------ (3)
}
a(1)
그리고 해당 코드는 아래 과정을 거쳐 작동한다:
- 2번째 줄: 변수 x 선언. 메모리 저장공간을 미리 확보하고, 확보한 공간의 주솟값을 변수 x에 연결
- 3번째, 4번째 줄: 다시 변수 x를 선언하나, 이미 있으므로 무시.
- 6번째 줄: x에 1을 할당. 우선 숫자 1을 별도의 메모리에 담고, x에 1주솟값 입력
- 7번째, 8번째 줄: 각 x출력. 모두 1이 출력됨!
- 9번째 줄: x에 2를 할당. 기존 주솟값을 2의 주솟값으로 바꿈
- 10번째 줄: x를 출력. 2가 출력됨.
- 함수 내부의 모든 코드가 실행됐으므로 실행 컨텍스트가 콜 스택에서 제거됨
함수 선언문과 함수 표현식
function a () {} // 함수 선언문. 함수 a가 곧 변수명
a(); // OK
var b = function () {} // (익명) 함수 표현식. 변수명 b가 곧 함수명.
b(); // OK
var c = function d() {} // 가명 함수 표현식. 변수명은 c, 함수명은 d.
c(); // OK
d(); // ERROR
주의할 점:
스코프, 스코프 체인, outerEnvironmentReference
스코프 체인
아래 코드 예시를 통해 스코프 체인을 확인해보자:
var a = 1;
var outer = function() {
var inner = function() {
console.log(a);
var a = 3;
};
inner();
console.log(a);
}
outer();
console.log(a)
// 결과: 1, 1
전역변수와 지역변수
- 정재남, 『코어 자바스크립트』, 위키북스(2019), p36-64.