执行上下文栈
操作系统对进程占用的内存空间的管理方式有两种:堆和栈
栈:是一种先进后出模式,而执行上下文栈,从名称上也可以看出,它是一种后进先出的模式
执行上下文就是当前 JavaScript 代码被【解析】和【执行时】所在环境的抽象概念
执行上下文三种类型
- 全局执行上下文: 这是默认的、最基础的执行上下文。不在任何函数中的代码都位于全局执行上下文中。它做了两件事:1. 创建一个全局对象,在浏览器中这个全局对象就是 window 对象。2. 将 this 指针指向这个全局对象。一个程序中只能存在一个全局执行上下文。
- 函数执行上下文: 每次调用函数时,都会为该函数创建一个新的执行上下文。每个函数都拥有自己的执行上下文,但是只有在函数被调用的时候才会被创建。一个程序中可以存在任意数量的函数执行上下文。每当一个新的执行上下文被创建,它都会按照特定的顺序执行一系列步骤。
- Eval 函数执行上下文: 运行在 eval 函数中的代码也获得了自己的执行上下文
执行上下文的生命周期
创建阶段 -> 执行阶段 -> 回收阶段
图文并茂观察执行上下文栈的执行生命周期变化
先来一段代码
function a () {
b();
}
function b () {
c();
}
function c() {
console.log('welcome');
}
debugger;
a();
通过控制台F11一步步调试
stack.gif
通过调试,观察控制台中的Call Stack可以看到下面一步步变化
- 还未执行,但此时栈中已有一个anonymous,也就是执行上下文
- 执行a(),此时上下文栈加入了a
- 执行b(),此时上下文栈加入了b
- 执行c(),此时上下文栈加入了c
- 执行完c(),此时上下文栈中移除c
- 执行完b(),此时上下文栈中移除b
- 执行完a(),此时上下文栈中移除a
- 程序执行完,只剩栈底anonymous,全局上下文只有在关闭浏览器窗口的时候才会被销毁
作用域链
作用域是在函数定义的时候就确定了。函数会保存一个内部属性[[scope]],这个变量会保存所有的父变量对象。查找的时候,会先在当前上下文变量对象中查找,如果找不到,就会向上级查找,一直找到所谓的全局对象。这个过程,查找多个变量对象所构成的链,则称为作用域链。
function a () {
function b () {
function c () {
}
}
}
a.[[scope]] = [
globalContext.VO
]
b.[[scope]] = [
aContext.AO,
globalContext.VO
]
c.[[scope]] = [
bContext.AO,
aContext.AO,
globalContext.VO
]
如果你看到这里了,那你肯定依旧一脸懵逼,因为这里是作为基础说明,并不会深入详解,有兴趣深入了解的请看新文章:全面攻克js中的堆栈内存及闭包
网友评论