자바스크립트 콜 스택이 어떻게 작동하는지는 모든 프론트엔드 개발자가 경력을 쌓으면서 한 번쯤은 물어봤을 질문이지만 제 생각에는 대부분의 곳에서 답변이 제공되지만 답변이 항상 명확하거나 이해하기 쉬운 것은 아닙니다. 그래서 이번 포스팅에서 주제를 다루기로 결정했습니다.
처음부터 시작해 보겠습니다. JavaScript 엔진은 코드를 한 줄씩 동기식으로 실행하고, 함수가 실행될 때마다 실행 컨텍스트(메모리 내 공간)을 생성하여 오직 존재하는 모든 범위 속성을 저장합니다. 해당 함수 내에서) 함수를 호출 스택에 추가합니다.
JavaScript는 스택 상단에 있는 함수의 코드만 실행하며, 함수가 종료되어 값을 반환하면 엔진은 호출 스택에서 해당 함수를 제거합니다 다음 작업을 시작합니다.
호출 스택이 비어 있으면 JavaScript 엔진은 다음 전역 컨텍스트에서 코드를 계속 실행합니다. 또는 동일한 내용으로 JavaScript 파일의 루트이며 어떤 기능에도 속하지 않습니다.
몇 가지 예를 한 줄씩 살펴보겠습니다.
const num1 = 2; const num2 = 5; function sum(a, b){ return a + b; } const result= sum(num1, num2); console.log(result) // 7
sum 함수를 정의하는 정말 간단한 코드입니다. 마지막으로 상수 result가 생성되고 num1 및 num2 인수를 사용하여 sum 실행 결과가 할당됩니다. 그러면 결과의 값이 콘솔에 인쇄됩니다.
앞의 설명이 너무 단순하거나 너무 복잡하여 아무 것도 설명하지 못한다고 생각되시면잠깐만 기다려 주세요, 흥미로운 내용으로 넘어가겠습니다.
자바스크립트 엔진이 무엇을 하는지한 줄씩 살펴보겠습니다. 첫 번째 줄에서 엔진은 num1 레이블을 생성하고 메모리 값 2.를 저장합니다.
const num1 = 2;
num2 레이블에 대해 동일한 작업을 수행합니다. num2 레이블을 생성하고 5. 값을 메모리에 저장합니다.
const num2 = 5;
전역 범위 내의 누군가가 num2 값을 요구할 때마다 엔진이 레이블을 변경하고 값을 입력5한다는 것입니다. 대신.
다음 줄을 계속 진행하겠습니다. 다음 줄은함수 sum입니다. 엔진이 무엇을 할 것이라고 생각합니까? 함수를 실행하거나 호출 스택에 추가할 것이라고 생각하시나요? 아니요! 엔진이 할 일은 sum이라는 이름의 새 레이블을 저장하고 메모리의 대괄호 안에 코드를 저장하는 것입니다. 또는 동일한 것은 함수 정의를 저장하고 sum 레이블에 할당하는 것입니다.
function sum(a, b){ return a + b; }
메모리를 시각적으로 볼 수 있다면 다음과 같은 내용을 볼 수 있을 것입니다.
Label name | Value in memory |
---|---|
num1 | 2 |
num2 | 5 |
sum | function definition |
정말 흥미로운 줄입니다. JavaScript 엔진은 다음 줄에 도달하면 결과라는 라벨을 생성하지만 이 시점에서는 아직 라벨에 어떤 값을 할당해야 할지 알 수 없습니다. 왜냐하면 값은 함수 실행의 결과입니다. 따라서 먼저 함수를 실행하고, 함수에 필요한 모든 작업을 수행하고, 반환 값에서 결과를 가져와.
const result= sum(num1, num2);
호출 스택에 함수를 추가하고 새 실행 컨텍스트도 생성합니다. 이는 새로운 메모리 공간입니다. JavaScript는 전역 컨텍스트와 충돌하지 않고 함수 내부에 있는 args 및 기타 모든 속성의 값을 저장할 수 있습니다.
First of all, the engine creates in memory the labels a and b which are the names given to the parameters, and it assigns the value of the arguments 2 and 5 respectively.
If we could see the memory at this specific moment, we would see something like this:
Label name | Value in memory |
---|---|
a | 2 |
b | 5 |
return | 2 + 5 = 7 |
In this case, the function is really simple and only returns the value of the sum between a and b, so the engine substitutes the parameters with the values of the arguments and returns the value to the global execution context. Finally, the function is removed from the call stack, and only the global context remains.
Call stack |
---|
Global |
At this point, the result of the function is assigned to the label result and we can print the value on console with the console log.
Let's take a look at how the global memory looks now:
Label name | Value in memory |
---|---|
num1 | 2 |
num2 | 5 |
sum | function definition |
result | 7 |
Did you noticed? the label result has a value of 7? and also sum still has the function definition inside.
Let's take a look at the next code:
const num1 = 2; const num2 = 5; function sum(a, b){ return a + b; } const result= sum(num1, num2); console.log(result) // 7 function sumThreeNumbers = (x,y,z) => { return sum(x, y) + z } const result2 = sumThreeNumbers(4,6,2) console.log(result2) // 12
The main difference is that now we have a new sumThreeNumbers function and we are creating a new result2 constant and assigning the value of running the function sumThreeNumbers with the arguments, 4, 6 and 2.
Let's take a look at how the call stack works when we run nested functions.
If we jump to the line when we define the constant result2 the global memory would look something like this:
Label name | Value in memory |
---|---|
num1 | 2 |
num2 | 5 |
sum | function definition |
result | 7 |
sumThreeNumbers | function definition |
Just as on the previous example, the JavaScript engine doesn't know what value to assign to the label result2, to get the value, first needs to execute the function sumThreeNumbers with the arguments. The function is added to the call stack, and a new execution context is created. The execution context would look like this:
Label name | Value in memory |
---|---|
x | 4 |
y | 6 |
z | 2 |
So the first thing that JavaScript does is create the parameter labels and assign the value provided by the arguments.
Now let's take a look at our call stack
Call stack |
---|
sumThreeNumbers |
Global |
As you can see, the call stack only has the sumThreeNumbers item (apart from the global context that is always present).
To be able to get the result value, the function sum needs to be executed first, so the engine will add the function to the call stack and create a new execution context for the sum function.
Call stack |
---|
sum |
sumThreeNumbers |
Global |
As the sum function is on top of the call stack, Javascript needs to run sum first to be able to continue running sumThreeNumbers.
This is how it's going to look the execution context for the function sum:
Label name | Value in memory |
---|---|
a | 4 |
b | 6 |
return | 4 + 6 = 10 |
아시다시피 _10을 반환하고 _콜 스택에서 제거됩니다
Call stack |
---|
sumThreeNumbers |
Global |
JavaScript는 sumThreeNumbers를 계속 실행하며 실행 컨텍스트는 다음과 같습니다.
Label name | Value in memory |
---|---|
x | 4 |
y | 6 |
z | 2 |
return | 10 + 2 = 12 |
12 값을 반환하고 호출 스택에서 제거됩니다.
Call stack |
---|
Global |
그러면 12 값이 result2 속성에 할당되고 12 값이 콘솔에 표시됩니다.
이 게시물이 JavaScript 호출 스택 작동 방식을 이해하는 데 도움이 되기를 바랍니다. 그렇다면 댓글과 좋아요를 남겨주세요. 다음 편에서 뵙겠습니다!
위 내용은 JavaScript 호출 스택 이해하기: 코드가 실제로 실행되는 방식의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!