什么是执行上下文
当 JS
引擎解析到可执行代码片段(通常是函数调用阶段)的时候,就会先做一些执行前的准备工作,这个 “准备工作”,就叫做 “执行上下文(execution context 简称 EC
)” 或者也可以叫做执行环境。
执行上下文 为我们的可执行代码块提供了执行前的必要准备工作,例如变量对象的定义、作用域链的扩展、提供调用者的对象引用等信息。
执行上下文的类型
javascript
中有三种执行上下文类型,分别是:
-
全局执行上下文——这是默认或者说是最基础的执行上下文,一个程序中只会存在一个全局上下文,它在整个
javascript
脚本的生命周期内都会存在于执行堆栈的最底部不会被栈弹出销毁。全局上下文会生成一个全局对象(以浏览器环境为例,这个全局对象是window
),并且将this
值绑定到这个全局对象上。 - 函数执行上下文——每当一个函数被调用时,都会创建一个新的函数执行上下文(不管这个函数是不是被重复调用的)
- Eval 函数执行上下文—— 执行在
eval
函数内部的代码也会有它属于自己的执行上下文,但由于并不经常使用eval
,所以在这里不做分析
执行上下文的内容
执行上下文是一个抽象的概念,我们可以将它理解为一个 object
,一个执行上下文里包括以下内容:
- 变量对象
- 活动对象
- 作用域链
- 调用者信息
变量对象(variable object
简称 VO
)
原文:Every execution context has associated with it a variable object. Variables and functions declared in the source text are added as properties of the variable object. For function code, parameters are added as properties of the variable object.
arguments
)初始化一个 “变量对象” 并将当前执行上下文与之关联 ,函数代码块中声明的 变量 和 函数 将作为属性添加到这个变量对象上。window
对象。VO
)被激活为活动对象(AO
)时,我们才能访问到其中的属性和方法。执行上下文栈
当一段脚本运行起来的时候,可能会调用很多函数并产生很多函数执行上下文,那么问题来了,这些执行上下文该怎么管理呢?为了解决这个问题,javascript
引擎就创建了 “执行上下文栈” (Execution context stack
简称 ECS
)来管理执行上下文。
顾名思义,执行上下文栈是栈结构的,因此遵循 LIFO
(后进先出)的特性,代码执行期间创建的所有执行上下文,都会交给执行上下文栈进行管理。
当 JS 引擎开始解析脚本代码时,会首先创建一个全局执行上下文,压入栈底(这个全局执行上下文从创建一直到程序销毁,都会存在于栈的底部)。
每当引擎发现一处函数调用,就会创建一个新的函数执行上下文压入栈内,并将控制权交给该上下文,待函数执行完成后,即将该执行上下文从栈内弹出销毁,将控制权重新给到栈内上一个执行上下文。
递归和栈溢出
stack overflow
)” 的错误。栈溢出错误经常会发生在 递归 中。尾递归优化
针对递归存在的 “爆栈” 问题,我们可以学习一下 尾递归优化。“递归” 我们已经了解了,那么 “尾” 是什么意思呢?“尾” 的意思是 “尾调用(Tail Call
)”,即函数的最后一步是返回一个函数的运行结果:
// 尾调用正确示范1 function a(x){ return b(x); } // 尾调用正确示范2 // 尾调用不一定要写在函数的最后为止,只要保证执行时是最后一部操作就行了。 function c(x) { if (x > 0) { return d(x); } return e(x); }
尾调用之所以与其他调用不同,就在于它的特殊的调用位置。尾调用由于是函数的最后一步操作,所以不需要保留外层函数的相关信息,因为调用位置、内部变量等信息都不会再用到了,只要直接用内层函数的调用记录,取代外层函数的调用记录就可以了,这样一来,运行尾递归函数时,执行栈永远只会新增一个上下文。
我们可以使用尾调用的方式改写下上面的累加递归:
运行之后怎么还是报错了 😳 ??裂开了呀。。。
其实,尾递归优化这种东西,现在没有任何一个浏览器是支持的(据说 Safari 13 是支持的),babel
编译也不支持。那 nodejs
里的 V8
引擎呢?它做好了,但是不给你用,官方回答如下:
Proper tail calls have been implemented but not yet shipped given that a change to the feature is currently under discussion at TC39.
总之,尾递归优化这个东西暂时还是不要想用到了,不过先了解个概念也是好的。
留言
您必须登陆 才能发表评论。