《用得上的前端知识》系列 - 你我都很忙,能用100字说清楚,绝不写万字长文
基本概念
调用栈:用来管理函数调用关系的一种后进先出的数据结构;
如何查看调用栈的信息
- 方法一:
-
- 打开开发者工具;
- 点击“Source”标签,在左边选择(点击)想查看的 JavaScript 代码;
- 点击中间代码区左侧的行号打上断点,然后刷新;
- 点击控制台右边的“Call Stack”来查看当前的调用栈的情况。
- 方法二:
-
- 使用 console.trace() 来输出当前的函数调用关系。
调用栈的溢出条件
调用栈有两个指标,最大栈容量和最大调用深度,满足其中任意一个就会栈溢出。
调用栈的工作过程
- JS 引擎根据代码类型创建执行上下文,并得到对应的可执行代码;
- 把创建的执行上下文压入栈底;
- 控制器进入位于栈顶的执行上下文,开始执行与之对应的可执行代码;
- 可执行代码执行完毕,与之对应的执行上下文出栈;
- 进入调用栈中下一个执行上下文,开始执行与之对应的代码,如此反复,直至剩下全局执行上下文。
注意:只有当整个应用程序结束的时候,调用栈才会被清空,所以程序结束之前, 调用栈最底部永远有个全局执行上下文。
能创建执行上下文的代码类型:
- 全局代码,当 JavaScript 执行全局代码的时候,会编译全局代码并创建全局执行上下文,而且在整个页面的生存周期内,全局执行上下文只有一份;
- 函数代码,当调用一个函数时,函数体内的代码会被编译,并创建函数执行上下文,一般情况下,函数执行结束之后,创建的函数执行上下文会被销毁;
- eval 函数代码,当使用 eval 函数的时候,eval 的代码也会被编译,并创建执行上下文。
举例说明
var a = 2;
function add(b,c){
return b+c;
}
function addAll(b,c){
var d = 10,
result = add(b,c);
return a+result+d;
}
addAll(3,6)
上述代码在执行过程中,调用栈的变化情况如下:
1、创建全局上下文,并将其压入栈底,如下图所示:
2、JavaScript 引擎开始执行全局代码。首先会执行 a=2 的赋值操作,全局上下文变量环境中 a 的值设置为 2;
3、调用 addAll 函数。当调用该函数时,JavaScript 引擎会编译该函数,并为其创建一个执行上下文,最后还将该函数的执行上下文压入栈中;
4、进入了函数代码的执行阶段,这里先执行的是 d=10 的赋值操作,addAll 函数执行上下文中的 d 由 undefined 变成了 10;
5、当执行到 add 函数调用语句时,同样会为其创建执行上下文,并将其压入调用栈;
6、当 add 函数返回时,该函数的执行上下文就会从栈顶弹出,并将 result 的值设置为 add 函数的返回值,也就是 9;
7、紧接着 addAll 执行最后一个相加操作后并返回,addAll 的执行上下文也会从栈顶部弹出,此时调用栈中就只剩下全局上下文了。