快速理解JavaScript调用栈

1,038 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第2天,点击查看活动详情

什么是调用栈?

调用栈是JavaScript维护出来的一种栈结构,作用就是用来分类管理代码的执行上下文的。 存储顺序是按照代码中函数的调用顺序。 通常把这种用来管理执行上下文的栈称为执行上下文栈,又称调用栈。

理解调用栈

现在我们看下面这串代码:

var a = 2

function p2(b,c){
  return b+c
}

function p1(b,c){
  var d = 10
  result = p2(b,c)
  return  a+result+d //2+9+10
}

console.log(p1(3,6));//21

以上代码中调用栈的执行过程是怎么样的呢?

  1. 首先创建全局执行上下文

1670153177103.png 我们可以看见已经把全局执行上下文压入栈中,全局作用域下的变量和函数已经声明好。接下来就是代码的执行。

  • 首先是将全局执行上下文中的a赋值为2
  • 而后是p1的调用,创建p1的执行上下文并压入栈中

7c6081a9210d614b4205a3827a67f1f.png

  • 创建好p1的执行上下文后执行代码。
  • 形参和实参统一,变量赋值d=10
  • result = p2(3,6)
  • p2的调用触发p2的上下文进入调用栈

e99ab6b6929b1e3b3c56fed0b5bfa83.png

  • p2的执行完毕返回值给p2的调用result,并且p2执行上下文出站。
  • p1的执行完毕接着就是p1执行上下文出站。
  • 执行console.log(p1(3,6))
  • 接着就是全局执行上下文出栈。意味着代码的执行完毕

以上就是这段代码的调用栈执行过程。

什么是栈溢出?

现在我们知道了调用栈是来管理执行上下文的数据结构的,遵循后进先出准则。但是调用栈是有大小限制的,当入栈的执行上下文超过一定的数目,JavaScript引擎就会报错。我们我这种报错叫栈溢出。

我们可以看看下面这串代码:

function add(a){
  return add(a+1)
}
console.log(add(1));

在调用add函数的时候,又调用了自己。这样的程序是不是一个没有停止条件的递归呢?

  • 不管在node环境还是在浏览器环境下,都会出现栈溢出的报错(超过了最大栈调用大小)

node环境

100fdd1233132df0fb07aadb7a95df0.png

浏览器环境

78e0e1595de6156dd1603d44fa4cc2b.png

所以在日常coding中,慎用递归是非常影响性能的,一不小心就会出现堆栈溢出的情况