什么是调用栈、作用域链和闭包?

前端 潘老师 1年前 (2023-11-13) 156 ℃ (0) 扫码查看

本文重点讲解什么是调用栈、作用域链和闭包?我们来一起学习下!

调用栈

调用栈是用来管理函数调用关系的一种数据结构。当一个函数被调用时,会将其添加到调用栈的顶部,然后执行该函数的代码。当函数执行完毕后,会将其从调用栈中移除。

调用栈的操作遵循”先进后出”(LIFO)的原则,即最后调用的函数先执行完毕,然后才能继续执行前一个调用的函数。通过调用栈,我们可以追踪函数的执行顺序,以及在函数执行过程中的上下文信息。

在拿到代码的那一刻,调用栈就已经生成,然后生成全局执行上下文,这里面会生成变量环境和词法环境(let 和const声明的变量会在词法环境中)。预编译找到a,值为undefined;add,值为function。开始执行,2赋值给了a,调用函数add。形成add的执行上下文,预编译开始编译函数内的内容,发现b,值为undefined。开始执行,10赋值给了b,return a = b,但是在自己的作用域内并不能找到a(按照 词法作用域->变量环境去查找),于是又去到全局中找到a=2。所以返回12。

作用域链

作用域链是通过词法环境来确定某一作用域的外层作用域,并形成一个查找变量的链状关系。在JavaScript中,每个函数都有自己的作用域,当在函数中访问一个变量时,会先从当前作用域开始查找,如果找不到,则会向外层作用域继续查找,直到找到变量或者到达全局作用域。

作用域链的形成是在函数定义阶段确定的,而不是在函数执行阶段。这意味着在函数定义时,就已经确定了函数在哪个作用域中执行,以及它可以访问哪些变量。

我们知道,栈是有大小的,所以为了防止作用栈被撑爆,当一条语句被执行完毕时,它在调用栈内形成的作用域(也就是执行上下文)将会被清除。

 

如上图:全局中有函数bar,foo,变量myName。因为调用了函数foo所以生成foo的执行上下文:有变量myName。执行bar的调用,bar的作用域中并没有东西,执行打印语句,输出myName的值,自己的作用域中没有,来到全局中找到myName=万总(函数声明在了哪里,outer的值就记在哪里)。

这里的outer是什么?其实是js的v8引擎自带的一个属性,它决定了函数在哪个作用域中执行,以及它可以访问哪些变量。 执行完打印语句,第7行执行完毕,bar的作用域出栈,紧接着foo也执行完毕,foo出栈,全局执行完毕,出栈。

闭包

闭包是JavaScript中一个重要的概念,它是由词法作用域规则支持的。当一个内部函数引用了外部函数中的变量,并且这个内部函数被外部函数返回时,就形成了闭包。

如图:全局中有test和res,执行,第12调用了函数test。来到test的作用域中,词法环境中有count,变量环境中有help。开始执行,把0赋值给count,return help,得到1。可以知道第12行已经执行完毕了,所以test作用域该出栈了,但我们注意到,函数test最后是return了函数help的,可以理解为return把它带离了函数test。如果就这么销毁他,我们可以认为这是有问题的。所以在test出栈时,会形成一个闭包,用来保存被带离的值。即当执行13行时,得到help返回的值为1,存在了闭包中,继续执行14行,不再是count=0 -> ++count,help返回值为1,而是在闭包中找到count=1,++count,help返回值为2,同理15行返回3。

闭包的特点是,即使外部函数已经执行完毕,但是内部函数仍然可以访问外部函数中的变量。这是因为闭包会将外部函数中被引用的变量保存在内存中,以供内部函数后续使用。

闭包的优点之一是实现了变量的私有化,即外部无法直接访问内部函数引用的变量。这可以提供更好的封装性和安全性。

然而,闭包也可能导致内存泄漏的问题。当一个函数返回一个闭包时,如果这个闭包持有大量的外部变量引用,而且不再被使用,那么这些变量将无法被垃圾回收机制释放,从而造成内存泄漏。

为避免闭包导致的内存泄漏问题,我们应该在不需要使用闭包时手动解除对外部变量的引用,或者及时释放闭包所占用的内存空间。

总结

总结: 本文详细介绍了JavaScript中的调用栈、作用域链和闭包。调用栈用于管理函数调用关系,作用域链通过词法环境确定了变量的查找顺序,而闭包则是形成了内部函数对外部函数变量的引用。闭包具有实现私有化变量的优点,但也存在内存泄漏的风险,需要注意及时解除变量引用或释放内存空间。了解和掌握这些概念对于理解JavaScript中的函数执行和变量作用域非常重要。

闭包虽好,可不要贪多哦,毕竟栈是有大小的。、

以上就是什么是调用栈、作用域链和闭包,你学会了吗?


版权声明:本站文章,如无说明,均为本站原创,转载请注明文章来源。如有侵权,请联系博主删除。
本文链接:https://www.panziye.com/front/11136.html
喜欢 (0)
请潘老师喝杯Coffee吧!】
分享 (0)
用户头像
发表我的评论
取消评论
表情 贴图 签到 代码

Hi,您需要填写昵称和邮箱!

  • 昵称【必填】
  • 邮箱【必填】
  • 网址【可选】