”工欲善其事,必先利其器。“—孔子《论语.录灵公》
首页 > 编程 > 揭秘 JavaScript 调用堆栈:代码的实际运行方式

揭秘 JavaScript 调用堆栈:代码的实际运行方式

发布于2024-09-02
浏览:757

Demystifying the JavaScript Call Stack: How Your Code Really Runs

How the JavaScript call stack works is something that every frontend developer has asked at least once in his career, and in my opinion, it's not a question that has been answered in most places, and the answers are not always clear or easy to understand. That's why I've decided to cover the topic in this post.

Let's start from the beginning. The JavaScript engine runs the code line by line synchronously, and every time a function is executed, it creates an execution context (a space in memory to store all the scoped properties that exist only inside that function) and adds the function to the call stack.

JavaScript only executes the code of the function that is on the top of the stack, and when a function finalises and returns its value, the engine removes the function from the call stack and starts working on the next one.

When the call stack is empty, the JavaScript engine continues running the code in the next global context, or what is the same, continues executing the lines that are in the root of the JavaScript file and don't belong to any function.

Let's see some examples, line by line:

const num1 = 2;
const num2 = 5;

function sum(a, b){
return a   b;
}

const result= sum(num1, num2);
console.log(result) // 7

This is a really simple code that defines 2 constants (num1 and num2) and then defines a function sum that sums 2 numbers and returns the result of the sum. Finally, the constant result is created, and the result of executing sum with the arguments num1 and num2 is assigned to it. Then the value of the result is printed on the console.

If you think that the previous explanation is too simple or too complex and does not explain anything, please bear with me, we are getting to the interesting stuff.

Let's see what the JavaScript engine is doing, line by line. In the first line, the engine creates a label num1 and stores in memory the value 2.

const num1 = 2;

The second line does the same for label num2. It creates a label num2 and stores in memory the value 5.

const num2 = 5;

What this means is that whenever someone inside the global scope requires the value of num2 the engine is going to change the label and put the value 5 instead.

Let's continue with the next line. The next line is the function sum. What do you think the engine is going to do? Do you think it is going to execute the function or add it to the call stack? Nope! What the engine is going to do is store a new label named sum and store the code inside the brackets in memory. Or what is the same, It's going to store the function definition and assign it to the sum label.

function sum(a, b){
return a   b;
}

if we could visually see the memory of the code that we've run so far, we would see something like this:

Label name Value in memory
num1 2
num2 5
sum function definition

The next line is a really interesting one. When the JavaScript engine reaches the next line, it creates the label result, but at this point, it doesn't yet know what value needs to be assigned to the label because the value is the result of executing a function, so first, it needs to execute the function, do whatever the function needs to do, and get the result from the return value.

const result= sum(num1, num2);

At this point, the engine adds the function to the call stack and also creates a new execution context, which is a new space in memory were JavaScript can store the value of the args and every other property that is inside of the function without colliding with the global context.

Call stack
sum
Global

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

As you know, it will return _10 _and it will be removed from the call stack

Call stack
sumThreeNumbers
Global

The JavaScript is going to continue executing the sumThreeNumbers and the execution context will look like this:

Label name Value in memory
x 4
y 6
z 2
return 10 2 = 12

It will return the value 12 and be removed from the call stack.

Call stack
Global

Then the value 12 will be assigned to the property result2 and the value 12 will be displayed in the console.

I hope this post has help you to understand how the JavaScript call stack works, if so please leave a comment and a like. I see you in the next one!

版本声明 本文转载于:https://dev.to/adriangube/demystifying-the-javascript-call-stack-how-your-code-really-runs-9m?1如有侵犯,请联系[email protected]删除
最新教程 更多>
  • Python高效去除文本中HTML标签方法
    Python高效去除文本中HTML标签方法
    在Python中剥离HTML标签,以获取原始的文本表示Achieving Text-Only Extraction with Python's MLStripperTo streamline the stripping process, the Python standard librar...
    编程 发布于2025-06-07
  • HTML格式标签
    HTML格式标签
    HTML 格式化元素 **HTML Formatting is a process of formatting text for better look and feel. HTML provides us ability to format text without us...
    编程 发布于2025-06-07
  • 为什么不使用CSS`content'属性显示图像?
    为什么不使用CSS`content'属性显示图像?
    在Firefox extemers属性为某些图像很大,&& && && &&华倍华倍[华氏华倍华氏度]很少见,却是某些浏览属性很少,尤其是特定于Firefox的某些浏览器未能在使用内容属性引用时未能显示图像的情况。这可以在提供的CSS类中看到:。googlepic { 内容:url(&#...
    编程 发布于2025-06-07
  • 为什么不````''{margin:0; }`始终删除CSS中的最高边距?
    为什么不````''{margin:0; }`始终删除CSS中的最高边距?
    在CSS 问题:不正确的代码: 全球范围将所有余量重置为零,如提供的代码所建议的,可能会导致意外的副作用。解决特定的保证金问题是更建议的。 例如,在提供的示例中,将以下代码添加到CSS中,将解决余量问题: body H1 { 保证金顶:-40px; } 此方法更精确,避免了由全局保证金重置引...
    编程 发布于2025-06-07
  • 将图片浮动到底部右侧并环绕文字的技巧
    将图片浮动到底部右侧并环绕文字的技巧
    在Web设计中围绕在Web设计中,有时可以将图像浮动到页面右下角,从而使文本围绕它缠绕。这可以在有效地展示图像的同时创建一个吸引人的视觉效果。 css位置在右下角,使用css float and clear properties: img { 浮点:对; ...
    编程 发布于2025-06-07
  • Spark DataFrame添加常量列的妙招
    Spark DataFrame添加常量列的妙招
    在Spark Dataframe ,将常数列添加到Spark DataFrame,该列具有适用于所有行的任意值的Spark DataFrame,可以通过多种方式实现。使用文字值(SPARK 1.3)在尝试提供直接值时,用于此问题时,旨在为此目的的column方法可能会导致错误。 df.withCo...
    编程 发布于2025-06-07
  • eval()vs. ast.literal_eval():对于用户输入,哪个Python函数更安全?
    eval()vs. ast.literal_eval():对于用户输入,哪个Python函数更安全?
    称量()和ast.literal_eval()中的Python Security 在使用用户输入时,必须优先确保安全性。强大的python功能eval()通常是作为潜在解决方案而出现的,但担心其潜在风险。 This article delves into the differences betwee...
    编程 发布于2025-06-07
  • 如何为PostgreSQL中的每个唯一标识符有效地检索最后一行?
    如何为PostgreSQL中的每个唯一标识符有效地检索最后一行?
    postgresql:为每个唯一标识符在postgresql中提取最后一行,您可能需要遇到与数据集合中每个不同标识的信息相关的信息。考虑以下数据:[ 1 2014-02-01 kjkj 在数据集中的每个唯一ID中检索最后一行的信息,您可以在操作员上使用Postgres的有效效率: id dat...
    编程 发布于2025-06-07
  • 如何检查对象是否具有Python中的特定属性?
    如何检查对象是否具有Python中的特定属性?
    方法来确定对象属性存在寻求一种方法来验证对象中特定属性的存在。考虑以下示例,其中尝试访问不确定属性会引起错误: >>> a = someClass() >>> A.property Trackback(最近的最新电话): 文件“ ”,第1行, AttributeError: SomeClass...
    编程 发布于2025-06-07
  • 如何在php中使用卷发发送原始帖子请求?
    如何在php中使用卷发发送原始帖子请求?
    如何使用php 创建请求来发送原始帖子请求,开始使用curl_init()开始初始化curl session。然后,配置以下选项: curlopt_url:请求 [要发送的原始数据指定内容类型,为原始的帖子请求指定身体的内容类型很重要。在这种情况下,它是文本/平原。要执行此操作,请使用包含以下标头...
    编程 发布于2025-06-07
  • 如何在其容器中为DIV创建平滑的左右CSS动画?
    如何在其容器中为DIV创建平滑的左右CSS动画?
    通用CSS动画,用于左右运动 ,我们将探索创建一个通用的CSS动画,以向左和右移动DIV,从而到达其容器的边缘。该动画可以应用于具有绝对定位的任何div,无论其未知长度如何。问题:使用左直接导致瞬时消失 更加流畅的解决方案:混合转换和左 [并实现平稳的,线性的运动,我们介绍了线性的转换。这...
    编程 发布于2025-06-07
  • 如何避免Go语言切片时的内存泄漏?
    如何避免Go语言切片时的内存泄漏?
    ,a [j:] ...虽然通常有效,但如果使用指针,可能会导致内存泄漏。这是因为原始的备份阵列保持完整,这意味着新切片外部指针引用的任何对象仍然可能占据内存。 copy(a [i:] 对于k,n:= len(a)-j i,len(a); k
    编程 发布于2025-06-07
  • 为什么PHP的DateTime :: Modify('+1个月')会产生意外的结果?
    为什么PHP的DateTime :: Modify('+1个月')会产生意外的结果?
    使用php dateTime修改月份:发现预期的行为在使用PHP的DateTime类时,添加或减去几个月可能并不总是会产生预期的结果。正如文档所警告的那样,“当心”这些操作的“不像看起来那样直观。 考虑文档中给出的示例:这是内部发生的事情: 现在在3月3日添加另一个月,因为2月在2001年只有2...
    编程 发布于2025-06-07
  • 如何高效地在一个事务中插入数据到多个MySQL表?
    如何高效地在一个事务中插入数据到多个MySQL表?
    mySQL插入到多个表中,该数据可能会产生意外的结果。虽然似乎有多个查询可以解决问题,但将从用户表的自动信息ID与配置文件表的手动用户ID相关联提出了挑战。使用Transactions和last_insert_id() 插入用户(用户名,密码)值('test','test...
    编程 发布于2025-06-07
  • Python环境变量的访问与管理方法
    Python环境变量的访问与管理方法
    Accessing Environment Variables in PythonTo access environment variables in Python, utilize the os.environ object, which represents a mapping of envir...
    编程 发布于2025-06-07

免责声明: 提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发到邮箱:[email protected] 我们会第一时间内为您处理。

Copyright© 2022 湘ICP备2022001581号-3