上下文
JS中广义的上下文就是一个个代码“块”,JS引擎使用上下文来管理语法的解析和运行代码。那么JS中有那些上下文,它们又是如何被创建和管理的呢。
全局执行上下文 Global Execution Context
在代码初始化阶段会生成全局执行上下午,其他包含了this,指向全局遍历。 浏览器的全局变量是window,Node的全局变量是global。
所谓的全局执行上下文,即使没有任何一行代码,也有两个被定义的变量。
Creation Execution
每个执行上下文都有两个阶段,Creation和Execution。在Creation阶段,主要进行一下四个工作:
- 创建全局对象
window或global - 创建并绑定this
- 为函数和变量开辟内存空间(变量,对象引用在堆,函数,对象在栈)
- 为变量初始化
undefined,函数申明存进内存
当完成了Creation阶段的四个工作,变会进入Execution阶段,一行行执行代码(先不考虑异步)。因为在执行前已经完成了变量初始化(let,const申明的除外),因此在一开头就已经可以使用大部分变量和函数了,虽然可能并不是我们想要的值。
显式申明的函数和赋值给变量的函数表达式不一样,前者会作为函数进行变量提升,后者变量提升初始化的结果是undefined,直接以函数的形式调用会出现typeError。
所谓的变量提升,就是变量初始化。
函数执行上下文
JS中只有两种执行上下文,在初始化创建的全局执行上下午和函数调用时创建的函数执行上下文。这两种上下文就对应了JS中的全局作用域和块状作用域。这两种上下文同样具有两个阶段Creation和Execution。那么在Creation阶段,相比全局上下文有什么区别呢?
- 不再创建全局变量,而是参数变量
arguments - 创建this变量
- 变量,函数分配内存
- 变量初始化undefined,函数存进变量
函数在JS引擎中会被存放在一个叫做执行栈的内存空间中,一旦函数执行完毕,函数就会从执行栈中被移除。 当我们访问一个变量时,首先从当前执行上下文中搜寻该变量。如果没有,全局执行上下文下会返回undefined,函数执行作用域会往上寻找。
闭包作用域
上面我们提到函数执行完毕会被从执行栈中移除,但是有一种情况例外,那就是函数内部嵌套定义了另一个函数。 当这种情况发生的时候,函数执行作用域还是会被移除,但是一个新的闭包作用域会替代生成。然后在这个闭包作用域中会生成嵌套函数的函数执行上下文。 当闭包作用域中不再包含任何函数执行上下文,就会被删除。