上一篇文章讲到深耕系列之静态作用域和动态作用域,提到函数作用域在定义时就决定了。大家可能还会有所迷茫,主要是对js执行过程不熟悉。
那么这篇文章会去深入理解执行上下文,理解js是如何执行的,执行上下文是执行的基础设置。
执行上下文介绍
简单来说,一段代码在执行过程中所需要的信息定义为执行上下文,javascript代码是在执行上下文中运行的。就如做菜时,锅碗瓢盆酱醋茶就相当于炒菜时的执行上下文。
那么执行上下文都记录了哪些内容?
执行上下文组成
上一篇文章提到的作用域,也是属于执行上下文的一部分,而执行上下文也包含了其他内容,不同的版本,它的组成还不一样:
在ES3中,包含三个部分
- scope:作用域,也常被叫为作用域链
- variable object:变量对象,用来存储变量
- this值
在ES5中,改进了命名方式,也包含三个部分
- lexical environment:词法环境,获取变量时使用
- variable environment:变量环境,声明变量时使用
- this值
在ES8中,this值被归纳到词法环境中,包含了更多的内容:
- lexical environment:词法环境,获取变量或this值时使用
- variable environment:变量环境,声明变量时使用
- code evaluation state:用于恢复代码执行位置
- Function: 任务是函数时用到,正在被执行的函数
- ScriptOrModule:任务是脚本或模块时用到,正在被执行的代码
- Realm:使用的基础库或内置对象
- Generator:仅生成器上下文使用到,表示当前生成器
以上介绍了执行上下文在ECMAScript各个版本的定义,网上的文章往往都没有梳理这些内容。
在这里就不讲解这些组成的详细情况,我会在后续文章再来阐述这部分内容。
为了便于理解,我们常常对执行上下文进行分类,那么在javascript中,执行上下文都有哪些类型?
执行上下文类型
javascript总共有三种执行上下文类型:
- 全局执行上下文:一整段script脚本执行时,会创建一个全局执行上下文。如浏览器在执行script脚本时,会先创建全局的window变量,然后设置this值为该全局对象。
- 函数执行上下文:在执行一个函数时,会创建一个函数执行上下文,每个函数都有自己的执行上下文。
- Eval执行上下文:执行在Eval函数内部的代码时,会创建Eval执行上下文,不过这个Eval很少使用。
当遇到函数中又调用其他函数,就会产生多个执行上下文,那么这些执行上下文是怎么关联起来的?
执行栈
执行栈用来存储代码运行中产生的所有执行上下文,具有先进后出的特性。
js引擎遇到javascript脚本时,先压入一个全局执行上下文,执行到函数,会再压入函数执行上下文。如果函数内部有调用其他函数,那么会继续压入函数执行上下文。函数执行完,会把栈顶的执行上下文弹出。
来看个例子:
let test = 1
function fn1() {
console.log('fn1')
fn2()
}
function fn2() {
console.log('fn2')
}
fn1()
根据以上代码,执行栈的变更如下:
分析如下:
- 浏览器加载以上代码,js引擎会创建全局上下文并压入执行栈。
- 当遇到fn1()调用时,js引擎会创建fn1函数上下文并压入执行栈。
- 当遇到fn1函数内部调用fn2函数,js引擎会创建fn2函数上下文并压入执行栈。
- fn2函数执行完毕,js引擎将栈顶的fn2函数上下文弹出。
- fn1函数执行完毕,js引擎将栈顶的fn1函数上下文弹出。
- 以上代码执行完毕,js引擎将全局上下文弹出。
总结
以上就是我对js执行上下文的理解,可能你会好奇执行上下文中的this,词法环境,变量环境到底是什么,后续文章会再总结变量对象和this等内容。如果觉得对你有帮助,请帮忙点个赞+评论+收藏,关注不失联。