자바스크립트 - 호출 스택

안녕하세요, 미래의 자바스크립트 마법사 여러분! 오늘 우리는 자바스크립트에서 가장 기본적인 개념之一的 호출 스택(Call Stack)에 대해 깊이 있게 탐구해보겠습니다. 이전에 들어보지 않았다면 걱정하지 마세요 - 이 튜토리얼이 끝나면 호출 스택의 전문가가 될 것입니다! 좋아하는 음료를 한 잔 가져와, 편안하게 앉아 이 흥미로운 여정에 함께 동행해 주세요.

JavaScript - Call Stack

호출 스택이란?

구체적인 내용에 들어가기 전에 간단한 비유로 시작해보겠습니다. 자신이 선택하는 모험 책을 읽고 있다고 상상해보세요. 책을 읽는 동안 각 결정 지점에 بوکه를 두고 있습니다. 길의 끝에 도달하면 마지막 بوکه로 돌아가 다른 길을 시도합니다. 자바스크립트에서 호출 스택은 이와 비슷하게 작동합니다 - 프로그램이 함수를 실행完毕한 후 어디로 돌아가야 할지 추적합니다.

기술적인 용어로는, 호출 스택은 Last In, First Out(LIFO) 원칙을 사용하여 임시로 함수 호출을 저장하고 관리하는 자료 구조입니다.

자바스크립트 호출 스택의 작동 방식

이제 자바스크립트에서 호출 스택이 어떻게 작동하는지 살펴보겠습니다. 간단한 예제부터 시작해 복잡도를 점진적으로 높이겠습니다.

예제 1: 간단한 함수 호출

function greet(name) {
console.log("Hello, " + name + "!");
}

greet("Alice");

이 코드가 실행될 때, 호출 스택에서 다음과 같은 일이 일어납니다:

  1. greet 함수가 스택에 추가됩니다.
  2. 함수가 실행되어 콘솔에 인사를 출력합니다.
  3. 함수가 완료되어 스택에서 제거됩니다.

fairly simple, isn't it? Now let's look at a slightly more complex example.

예제 2: 중첩된 함수 호출

function multiply(a, b) {
return a * b;
}

function square(n) {
return multiply(n, n);
}

function printSquare(n) {
var squared = square(n);
console.log(n + " squared is " + squared);
}

printSquare(4);

printSquare(4)를 실행할 때, 호출 스택은 다음과 같이 작동합니다:

  1. printSquare(4)가 스택에 추가됩니다.
  2. printSquare 내부에서 square(4)가 호출되어 스택에 추가됩니다.
  3. square 내부에서 multiply(4, 4)가 호출되어 스택에 추가됩니다.
  4. multiply가 완료되어 스택에서 제거됩니다.
  5. square가 완료되어 스택에서 제거됩니다.
  6. printSquare 결과를 로그하고 완료되어 스택에서 제거됩니다.

스택이 함수 호출과 완료됨에 따라 커지고 작아지는 것을 볼 수 있나요? 레고 블록으로 짓고 허물는 탑과 같은 것입니다!

예제 3: 재귀 함수

재귀 함수는 호출 스택이 커지는 것을 잘 설명할 수 있는 완벽한 예제입니다. 계산하기 쉬운 예제를 보겠습니다: 팩토리얼 계산.

function factorial(n) {
if (n === 1) {
return 1;
} else {
return n * factorial(n - 1);
}
}

console.log(factorial(5));

factorial(5)를 호출할 때, 호출 스택은 다음과 같이 보입니다:

  1. factorial(5)가 추가됩니다.
  2. factorial(4)가 추가됩니다.
  3. factorial(3)가 추가됩니다.
  4. factorial(2)가 추가됩니다.
  5. factorial(1)가 추가됩니다.
  6. factorial(1)이 1을 반환하고 스택에서 제거됩니다.
  7. factorial(2)가 2 * 1을 계산하여 2를 반환하고 스택에서 제거됩니다.
  8. factorial(3)가 3 * 2를 계산하여 6을 반환하고 스택에서 제거됩니다.
  9. factorial(4)가 4 * 6을 계산하여 24를 반환하고 스택에서 제거됩니다.
  10. factorial(5)가 5 * 24를 계산하여 120을 반환하고 스택에서 제거됩니다.

와우! 많은 푸시와 팝이 있었죠? 하지만 이게 바로 자바스크립트가 모든 중첩된 함수 호출을 추적하는 방법입니다.

자바스크립트 호출 스택 오버플로

이제 호출 스택이 어떻게 작동하는지 이해했으므로, 잘못된 일이 발생할 때 어떤 일이 일어나는지 이야기해보겠습니다. "스택 오버플로(stack overflow)"라는 용어를 들어보셨나요? 이는 단순히 절망한 프로그래머들을 위한 웹사이트만이 아닙니다 - 코드에서 실제로 발생할 수 있는 오류입니다.

스택 오버플로는 함수 호출이 너무 많아 호출 스택이 크기 제한을 초과할 때 발생합니다. 가장 흔한 원인은 무한 재귀입니다!

예제 4: 스택 오버플로

function causeStackOverflow() {
causeStackOverflow();
}

causeStackOverflow();

이 코드를 실행하면 "Maximum call stack size exceeded"와 같은 오류 메시지가 나타납니다. 레고 블록으로 달 수 있는 토우를 짓는 것과 같습니다 - 결국 블록이 부족하거나 메모리가 부족해집니다!

재귀 함수에서 스택 오버플로를 피하려면 항상 재귀를 종료할 수 있는 적절한 기저 사례를 보장해야 합니다.

호출 스택 메서드

자바스크립트는 호출 스택을 직접 조작할 수 있는 메서드를 제공하지 않지만, 디버깅과 호출 스택 이해에 유용한 관련 함수가 있습니다:

메서드 설명
console.trace() 콘솔에 스택 트레이스를 출력합니다
Error.stack 비표준 속성으로, 스택 트레이스를 반환합니다

console.trace()를 사용하는 빠른 예제:

function func1() {
func2();
}

function func2() {
func3();
}

function func3() {
console.trace();
}

func1();

이는 다음과 같은 호출 순서를 출력합니다: func3 -> func2 -> func1.

결론

이제 여러분은 자바스크립트의 흥미로운 세계에서 호출 스택을 여행한 경험을 가지게 되었습니다. 간단한 함수 호출에서 복잡한 재귀까지, 자바스크립트가 코드에서 어디에 있는지 추적하는 방법을 이제 이해하고 계신 것입니다.

기억하세요, 호출 스택은 친절한 어시스턴트처럼 코드의 장소를 기억합니다. 하지만 어시스턴트처럼, 그 한계도 있습니다 - 스택 오버플로를 피하려면 주의해야 합니다!

자바스크립트 여정을 계속하면서 호출 스택을 기억하세요. 이를 이해하면 더 나은 코드를 작성하고 디버깅을 쉽게 할 수 있습니다. 행복한 코딩을 기원하며, 항상 완벽하게 균형 잡힌 스택을 유지하시길 바랍니다!

Credits: Image by storyset