一、什么是执行栈?
执行栈是一种数据结构,用于存放各种函数的执行上下文。执行上下文是一种抽象的东西,所有的 JS 代码在运行时都是在执行上下文中进行的。而 JS 有三种执行上下文,分别是:
1:全局执行上下文,默认的,在浏览器中是 window 对象,并且 this 在非严格模式下指向它。
2:函数执行上下文,JS 的函数每当被调用时会创建一个上下文。
3:Eval 执行上下文,eval 函数会产生自己的上下文。
当我们的 JS 的代码开始运行的时候,就会产生一个全局执行上下文,这个全局执行上下文会被加入到执行栈的最底部,我们称之为为栈底。之后当每一个函数执行前,会创建函数自己的的执行上下文然后加入到执行栈中,函数调用之后,函数执行上下文销毁,出栈。以下看代码。
<
ok,定义了两个函数a和b,JS 运行时创建全局上下文,入栈,位于栈底,全局上下文里面有a和b两个变量指向对应函数。接下来执行 “console.log("global");”,这里console调用了log函数,执行这条语句前创建了log的函数执行上下文,压入执行栈中,位于全局上下文上方。执行log函数控制台打印出“global”之后,log函数执行完毕,函数上下文随之销毁,出栈。
之后a函数执行,a函数中console调用log函数,同上,创建log上下文入栈,函数执行打印“a”之后log的上下文销毁,出栈。接下来执行b函数,执行前创建b的函数上下文并压入栈中。
b函数的运行,此时console.log("b"),创建log函数执行上下文,压入栈中,位于b的函数执行上下文上方。
随后控制台打印输出log函数的执行结果,log函数执行完毕,此时 JS 代码全部运行完毕,销毁log函数上下文出栈,销毁b函数上下文出栈,最后销毁全局执行上下文出栈,执行栈全部清空。
--------- 2020/5/8 先写这么多 ---------
二、求斐波拉契数列的第N位的值
首先要知道斐波拉契数列是长这样子的:“ 1、1、2、3、5、8、13、21、34、…… ”特点是第n位的值等于它去两位数之和。我们用递归的方式求斐波拉契数列的第N位的值,结合执行栈和执行上下文来看这个递归写法。
<
创建完全局上下文压入栈底之后,来到打印函数log,有一个参数n==4的getFeibo函数执行,创建getFeibo函数的上下文,里面的参数n等于数值4,在执行getFeibo(4)中,通过了if判断,此时getFeibo( 4 )中 return geFeibo( 3 ) + getFeibo( 2 ) 。
随后 JS 引擎运行 getFeibo( 4 ) 中return语句中第一个表达式 geFeibo( 3 )
创建 getFeibo(3)的函数执行上下文,上下文里参数n等于数值3,n等于3通过了if判断,此时getFeibo( 3 )中 return getFeibo ( 2 ) + getFeibo ( 1 ) 。
随后 JS 引擎运行 getFeibo( 3 ) 中return语句中第一个表达式 geFeibo( 2 )
同上创建 getFeibo(2)的执行上下文压入执行栈中,位于getFeibo(3)上下文的上部,此时getFeibo(2)的上下文位置也是在执行栈的栈顶。
此时运行n等于2的getFeibo函数,n等于2不能通过if判断,getFeibo(2)函数运行结束 返回结果是 1 ,上下文销毁出栈。
现在,位于栈顶的是getFeibo(3)的执行上下文,JS 引擎继续运行,回到getFeibo(3)的上下文里来,它的return语句此时是 return 1 + getFeibo(1)
JS 引擎执行getFeibo(3)中return语句里的第二条表达式 getFeibo(1)
创建getFeibo(1)的执行上下文入栈位于栈顶,n等于1,getFeibo(1)返回结果 1 ,函数执行完毕上下文销毁出栈。
到此,getFeibo(3)return 1 + 1 ,返回结果为 2,函数运行结束上下文销毁出栈。
JS 引擎回到 getFeibo(4)的执行上下文中,此时getFeibo(3)已经返回结果为 2 ,它的return语句变成了 return 2 + getFeibo(2)。运行第二个表达式getFeibo(2),
n等于2无法通过if判断返回结果 1 。
最后,getFeibo(4)return语句的第二个表达式也已得出结果,return 2 + 1 ,getFeibo(4)运行结束返回结果为 3 。销毁上下文。
执行console的log函数,创建log函数的的上下文入栈位于全局上下文上方(此时为栈顶)。打印输出结果 3 .函数结束,log函数上下文销毁,JS代码全部跑完,全局上下文销毁。整个执行栈清空。
熟悉了这次用递归求斐波拉契数列第n位值之后,不难发现一个问题,整个代码的执行过程都是在创建上下文再销毁上下文,如果getFeibo函数中没有这条if语句做拦截的话,将会无限的递归下去,也就会无限的创建函数执行上下文加入执行栈中,最后控制台上将会报错:
Uncaught RangeError: Maximum call stack size exceeded
超出执行栈最大尺寸,也就是造成内存泄漏,内存不够用。JS引擎永远是先执行栈顶的上下文,当无限递归的时候,会一直往执行栈的栈顶加入上下文,代码永远跑不完。
------ 本篇完结 -----