# 执行上下文、作用域

执行上下文是代码的执行环境,通常由三种(Global、function、eval)。

JavaScript引擎会以栈的方式处理他们。 代码执行过程中,每生成一个执行上下文,都会将这个上下文放到栈顶,待执行完毕,就会出栈。

  • 单线程
  • 同步执行,只有栈顶的上下文处于执行状态,其他的都需要等待
  • 全局上下文只有唯一一个,浏览器关闭时出栈
  • 函数的执行上下文没有个数限制
  • 每次单个函数的调用,就会创建新的执行上下文,调用自身函数也会创建

# 执行上下文生命周期

  • 创建阶段

在这个阶段,执行上下文会分别创建变量对象、建立作用域链、确定this的指向。

变量对象的创建又经历了以下几个过程:

1、建立arguments对象。检查当前上下文的参数,建立该对象下的属性和属性值。

2、检查当前上下文的函数声明。并在变量对象中建立对应属性,属性值为函数所在内存地址。如果属性名已经存在,则会用心属性值覆盖。

3、检查当前上下文的变量生命。每找到一个变量生命,就在变量对象中以变量名建立一个属性,如果属性已经存在,为了防止同名的函数被修改为undefined,则会直接跳过,原有属性值不会被修改。(所以说函数的优先级更高)

  • 代码执行阶段

创建完成后,开始执行代码,完成变量赋值、函数引用、执行其他代码。

一般函数执行完就会被销毁。闭包例外。

# 执行上下文中的内容

# 变量对象(variable object 简称 VO)

JS 引擎会用当前函数的参数列表(arguments)初始化一个 “变量对象” 并将当前执行上下文与之关联 ,函数代码块中声明的 变量 和 函数 将作为属性添加到这个变量对象上,函数表达式不会放到变量对象上。

# 活动对象(activation object 简称 AO)

当函数进到执行阶段,原本的变量对象,被激活成活动对象。

# 作用域

一套规则,规定了可以查找和使用的变量。

  • JavaScript中只有全局作用域和函数作用域。

  • 作用域和执行上下文不同。一个是环境、一个是规则。

    代码执行分为编译执行阶段。编译阶段,由编译器完成,将代码编译成可执行代码,这个阶段会确定作用域规则。执行阶段由引擎完成,主要是执行代码,执行上下文在这个阶段创建。

# 作用域链

作用域链由当前环境和上层环境的一系列变量对象组成,保证了当前执行环境对变量和函数的有序访问。

当查找变量的时候,会从当前的上下文变量对象中查找,如果没能够找到,会向上(父级)的变量对象中查找,一直找到全局上下文的变量对象。

# 闭包

闭包是一种特殊的对象。

由两部分组成,执行上下文A,以及在该执行上下文中创建的函数B。

当B在外部调用执行的时候,如果访问了A中的变量,闭包就会产生。

闭包会阻止垃圾回收。

# 应用场景

  • 柯理化
  • 模块

# this

this的指向由调用者确定。

this指向。

  • 默认。
  • 对象调用
  • bind/call/apply
  • new

# 参考

面试官:说说执行上下文吧

理解 JavaScript 中的执行上下文和执行栈

前端基础进阶