在 JavaScript 中,执行上下文(Execution Context)是代码在运行时的环境,决定了变量或函数的访问权限以及它们的行为。每当 JavaScript 代码执行一段代码块时,都会创建一个新的执行上下文。
执行上下文的类型
JavaScript 中有三种执行上下文:
全局执行上下文:这是默认的、最基础的执行上下文。浏览器中的全局上下文就是
window
对象,而在 Node.js 中则是global
对象。在全局执行上下文中定义的变量和函数都可以在整个程序中访问。函数执行上下文:每次调用一个函数时,都会为该函数创建一个新的执行上下文。每个函数都有自己的执行上下文,且相互独立。
Eval 执行上下文:当代码在
eval()
函数中执行时,会创建一个独立的执行上下文(不常用)。
执行上下文的生命周期
每个执行上下文都会经历三个阶段:
创建阶段:
- 变量对象(Variable Object,VO):在创建阶段,变量、函数声明和函数的形参都会被存储在变量对象中。在函数执行上下文中,变量对象通常称为“活动对象”(Activation Object,AO)。
- 词法环境(Lexical Environment):用来存储函数中的变量和外部变量的引用,包括作用域链的维护。
- This 绑定:确定在这个执行上下文中的
this
值。对于全局上下文,this
通常指向window
(或global
)。
执行阶段:
- 在这一阶段,代码会按照顺序执行,变量会被赋值,函数会被调用。
销毁阶段:
- 当代码执行完毕,执行上下文会被销毁,内存资源会被释放。
执行栈(调用栈)
JavaScript 是单线程的,使用执行栈(调用栈)来管理多个执行上下文。执行栈是一个后进先出(LIFO)的数据结构,当新的执行上下文被创建时,它会被压入执行栈的顶部。当上下文执行结束时,它会被从栈顶弹出。
- 全局执行上下文永远位于栈底。
- 每当调用一个函数时,函数的执行上下文会被压入栈顶。
- 当函数执行完毕,它的执行上下文会从栈中弹出,控制权返回到上一个上下文。
作用域链和闭包
每个执行上下文都有一个与之关联的作用域链,用来保证当前执行代码对变量的有序访问。当在一个函数中定义函数时,内部函数会记住外部函数中的变量,即闭包的形成。
这些概念在理解 JavaScript 的执行流程、作用域、闭包、以及事件循环等方面非常重要。