详解作用域、作用域链与执行环境

前言

当我们定义了变量之后,它们存放在哪里?当我们需要使用它们时,我们的程序又是怎么找到这些变量的?
这就涉及到了接下来要说的作用域。

作用域

当JavaScript引擎负责整个代码的执行过程时,作用域作为它的好伙伴,将所有声明的变量组成的一系列查询,收集和维护起来,制定了一套严格的规则,用来确定当前执行的代码对这些变量的访问权限。

作用域的作用
var a = 'hellow';

当面对这样一条执行语句时,并不单单是我们所想象的简单的一条声明,引擎会认为这里有两条声明,分别在编译器编译时处理,和引擎运行时处理。

我们知道,一般的程序在编译阶段,会经过大概三个阶段——词法分析、语法分析、代码生成。
首先我们的编译器会进入词法分析的阶段,将这条语句拆分成词法单元,然后然后解析为一个语法树,但是在代码生成的阶段,它会经历以下几个步骤:

  1. 遇到var a,编译器会询问作用域,在当下的这个作用域内,是否已经存在了一个相同名称的变量。如果是的话,编译器就会忽略这一条声明继续编译。如果否,编译器就会要求作用域在当下的作用域内声明一个新的变量,并且命名a。

  2. 接着编译器要为引擎生成运行时需要的代码,这些代码要用来处理a = 'hello’这个操作。所以引擎在运行时又会向作用域发起询问,在当下的作用域里,是否存在一个叫“a”的变量。存在就将“hello”赋值给a。如果不存在,编译器会沿着作用域链一直向上进行查找(关于作用域链在后面我会进行更详细的解释),找到a的时候就会进行赋值操作。如果一直找到全局环境结束还没有找到a,就会抛出一个错误。

作用域链

那么我们现在已经知道,作用域制定了根据名称查找变量的规则,引擎对作用域发起询问之后,就能知道当前的作用域内有没有自己想找的变量。那么如果当前作用域没有,引擎应该接下来应该去问谁呢?

我们刚才说了,引擎会沿着作用域链向上继续查找,直到找到或是抵达全局环境为止,这说明我们的作用域是不止一个的。

当一个块或函数嵌套在另一个块或函数中时,就发生了作用域的嵌套,形成了作用域链。

在《你不知道JavaScript(上卷)》中,将作用域链比喻成一个高大的建筑。
一楼代表当前的作用域,也就是我们执行到对应代码时所处的为止,当我们在这一层楼没有查到想要的变量时,就会坐电梯上一楼继续查找。
一旦我们到了顶楼,也就是全局作用域的时候还没有找到我们的变量,就会停止我们的查找,并抛出错误。

执行环境

执行环境又称执行上下文。

或许有很多人将作用域与执行环境混淆,因为它们的功能看起来非常相似——作用域制定了按名称查找变量的规则,而执行环境定义了变量或函数有权访问的其他数据。

但它们两个并不是一样的东西。

当执行到一段可执行代码时,会创建一个对应的执行环境,即执行上下文。JavaScript引擎使用执行上下文栈来对执行上下文进行管理。
我们知道,栈具有先进后出的特点,而我们最大的执行环境——全局环境,与程序具有同样的生命周期,在程序一开始运行时就被压入栈底,程序结束时才会出栈。

执行上下文创建的时候,变量对象作用域链就会被创建。

变量对象

每一个执行上下文都有一个对应的变量对象,该上下文内定义的所有变量和函数都保存在这个变量对象里。我们的代码是无法访问到这个对象的,但是解析器在对数据进行处理时,会在后台使用它。

变量对象在创建时:

  1. 首先会建立arguments对象,检查对应的执行环境中的参数,建立arguments下的属性和属性值。
  2. 开始进行函数声明,在arguments对象内以函数的名称建立一个属性,值是指向函数在堆内存中地址的一个引用。如果这个以这个函数名命名的属性已经存在,那么就会被新的引用值所替换。
  3. 进行变量声明。在arguments对象中以变量名建立属性,值为undefined。如果已经存在这个名称的属性,那么为了防止覆盖调同名的函数,会跳过这个声明,原属性值不会被修改。
活动对象

当这段代码进入到执行阶段,变量对象就会变成活动对象,里面的属性值就能够被访问了。

总结

所以变量对象和活动对象是同一个对象处在执行上下文的不同生命周期的结果。而在创建执行上下文的时候,变量对象和作用域链都被创建。
每个执行上下文都会关联着一个变量对象,而作用域是函数维度的,或者说是执行上下文维度的。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值