js打印到控制台_JS执行栈,执行上下文,从求斐波拉契数列第n位看递归

7a7adeeeb2acc14ca556507971cf32dc.png

一、什么是执行栈?

执行栈是一种数据结构,用于存放各种函数的执行上下文。执行上下文是一种抽象的东西,所有的 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函数执行完毕,函数上下文随之销毁,出栈。

93b5969f7b94d13a3e68cc5871dce744.png

815a0b9a88663b4358417cf37c9212b3.png
log函数上下文入栈,执行后控制台打印输出语句,log函数执行结束,上下文销毁并出栈

之后a函数执行,a函数中console调用log函数,同上,创建log上下文入栈,函数执行打印“a”之后log的上下文销毁,出栈。接下来执行b函数,执行前创建b的函数上下文并压入栈中。

6d743fc87d9ac0755f1064579efb602f.png
b函数运行前创建b函数上下文入栈

b函数的运行,此时console.log("b"),创建log函数执行上下文,压入栈中,位于b的函数执行上下文上方。

c60cd2bc39abce0f9fba3dd0cd74398f.png

随后控制台打印输出log函数的执行结果,log函数执行完毕,此时 JS 代码全部运行完毕,销毁log函数上下文出栈,销毁b函数上下文出栈,最后销毁全局执行上下文出栈,执行栈全部清空。

aa59232ddfc49b44142d6e4835bde613.png
从上往下依次出栈

--------- 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)的上下文位置也是在执行栈的栈顶。

a189e4ef2b6008e99de06149eeef918f.png

此时运行n等于2的getFeibo函数,n等于2不能通过if判断,getFeibo(2)函数运行结束 返回结果是 1 ,上下文销毁出栈。

现在,位于栈顶的是getFeibo(3)的执行上下文,JS 引擎继续运行,回到getFeibo(3)的上下文里来,它的return语句此时是 return 1 + getFeibo(1)

b9993e19aaf1546dbf5ed10d0df1c39e.png

JS 引擎执行getFeibo(3)中return语句里的第二条表达式 getFeibo(1)

创建getFeibo(1)的执行上下文入栈位于栈顶,n等于1,getFeibo(1)返回结果 1 ,函数执行完毕上下文销毁出栈。

7f0559ba3ba06526114d0d6f948504ff.png
getFeibo(1)执行结束,返回 1 ,上下文销毁出栈

到此,getFeibo(3)return 1 + 1 ,返回结果为 2,函数运行结束上下文销毁出栈。

2e1e98018ca28a96fa501abaad80edeb.png

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引擎永远是先执行栈顶的上下文,当无限递归的时候,会一直往执行栈的栈顶加入上下文,代码永远跑不完。

------ 本篇完结 -----

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值