浏览器工作原理:浅析调用栈 - 执行上下文、后进先出
当一段代码被执行时,JavaScript 引擎先会对其进行编译,并创建执行上下文。那到底什么样的代码才算符合规范。
那么接下来我们就来明确下,哪些情况下代码才算是“一段”代码,才会在执行之前就进行编译并创建执行上下文。一般说来,有这么三种情况:
1、当 JavaScript 执行全局代码的时候,会编译全局代码并创建全局执行上下文,而且在整个页面的生存周期内,全局执行上下文只有一份。
2、当调用一个函数的时候,函数体内的代码会被编译,并创建函数执行上下文,一般情况下,函数执行结束之后,创建的函数执行上下文会被销毁。
3、当使用 eval 函数的时候,eval 的代码也会被编译,并创建执行上下文。
好了,又进一步理解了执行上下文,那本节我们就在这基础之上继续深入,一起聊聊调用栈。学习调用栈至少有以下三点好处:
1、可以帮助你了解 JavaScript 引擎背后的工作原理;
2、让你有调试 JavaScript 代码的能力;
3、帮助你搞定面试,因为面试过程中,调用栈也是出境率非常高的题目。
比如你在写 JavaScript 代码的时候,有时候可能会遇到栈溢出的错误,如下图所示:
![](https://i-blog.csdnimg.cn/blog_migrate/a6806034a10c81389a8ec64a8cb720ac.png)
那为什么会出现这种错误呢?这就涉及到了调用栈的内容。你应该知道 JavaScript 中有很多函数,经常会出现在一个函数中调用另外一个函数的情况,调用栈就是用来管理函数调用关系的一种数据结构。因此要讲清楚调用栈,你还要先弄明白函数调用和栈结构。
一、什么是函数调用
函数调用就是运行一个函数,具体使用方式是使用函数名称跟着一对小括号。下面我们看个简单的示例代码:
var a = 2
function add(){
var b = 10
return a+b
}
add()
这段代码很简单,先是创建了一个 add 函数,接着在代码的最下面又调用了该函数。
那么下面我们就利用这段简单的代码来解释下函数调用的过程。
在执行到函数 add() 之前,JavaScript 引擎会为上面这段代码创建全局执行上下文,包含了声明的函数和变量,你可以参考下图:
![](https://i-blog.csdnimg.cn/blog_migrate/b9f6618bb69c5be7231d8d0b508c69d3.png)
从图中可以看出,代码中全局变量和函数都保存在全局上下文的变量环境中。