只调用一次_JavaScript运行机制 - 调用栈

背景

如果你试图运行下面的代码:

function func(){
    func()
}

func()

相信你会得到如下的结果

9c478127dd54f64ff294c86398025d94.png

调用栈是用来管理函数调用关系的一种数据结构。让我们先来看看函数调用栈结构。


函数调用

函数调用就是运行一个函数,是以在函数名后加小括号的方式调用函数。在变量提升的文章中,我们已经了解到在函数运行前会创建执行上下文,并且在每一次函数被调用是都会创建一个执行上下文。所以当函数调用另一个函数时,会产生多个执行上下文。

GlobalExectionContext = {
  ThisBinding: <Global Object>,
  LexicalEnvironment: { ... },
  VariableEnvironment: { ... }
}

FunctionExectionContext = {
  ThisBinding: <Global Object>,
  LexicalEnvironment: { ... },
  VariableEnvironment: { ... }
}

FunctionExectionContext = {
  ThisBinding: <Global Object>,
  LexicalEnvironment: { ... },
  VariableEnvironment: { ... }
}

...

此时JavaScript引擎就需要使用一种数据结构来管理这些执行上下文


栈是一种线性的有序的数据集合,它的添加和删除操作只允许在集合的尾部进行,所以它具有先进后出的特点。

603d65edc628f47ae914ccf1ef1f657d.png

由于入栈和出栈操作在同一端处理,如果不停的入栈而不出栈的话,整个集合就会出现被占满的情况。


JavaScript调用栈

JavaScript引擎利用了这种数据结构来管理执行上下文的。函数被调用时向调用栈压入函数执行上下文,函数运行结束时函数执行上下文被弹出。所以文章开头的那段代码会形成如下的调用栈。

eeffad2388ff0cc5296bdb0f9876eef6.png

只有入栈而没有出栈,直到调用栈中的执行上下文达到最大数量,就会报错结束。

在开发过程中,利用浏览器控制台工具可以很好的观察JavaScript调用栈的信息,帮助我们更好的调试程序。 我们在之前的代码中加入断点。

运行第一次。

77ac9d8784826119c6d9da905c17bbcb.png

跳过一次断点后,可以明显的看出调用栈的变化。

77c7ca91bc0fb6fb28cd354e59c01c9a.png

总结

  • JavaScript调用栈使用栈数据结构管理着执行上下文。执行上下文随着函数的调用而入栈,随着运行结束而出栈。
  • 调用栈满时会报错。
  • 当需要使用递归时,可考虑使用迭代替换以减少执行上下文的数量。

当我们在实际开发中,势必会使用很多第三方库或框架,当发生报错时可利用控制台的调用栈工具快速定位问题。

0eeee985b5b77d4071503925400d3563.png

对于开发者工具的使用,后面会有单独的章节讲解。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值