JavaScript基础篇03:作用域、作用域链和执行上下文

166 阅读3分钟

作用域

  1. 什么是作用域(scope)?

作用域可以从字面理解为变量能够产生作用的区域

我们要知道变量能够产生作用的两种方式是:

LHS查询(赋值查询,要找到变量本身)和RHS查询(取值查询,只关心变量的源值)。

因此作用域其实就是可以帮助引擎确定在哪里查询、怎么查询变量的一套规则,也就是说它管理着变量的可访问性

作用域包括三种:全局作用域、函数作用域、块级作用域

  1. 作用域和上下文有什么区别?

(1) 什么是执行上下文?

上下文可以理解为代码执行流所处的当前环境

以函数举例,当调用函数时,代码执行流会进入该函数,此时会为这个函数调用创建一个执行上下文,并把这个上下文推进上下文栈上,表示当前代码执行流正处于此上下文的环境中。而函数执行完毕后,上下文就会被摧毁,因为代码执行流已经离开了这个函数,环境也就不需要存在了。

每个上下文都会与一个变量对象相关联,变量对象中保存着当前上下文可以访问的变量和函数。因为代码的执行一定会涉及对变量的操作,所以上下文一定会和一个变量对象捆绑。这里的变量对象可以看作作用域在上下文中的体现。

(2)作用域和上下文有什么区别?

  • 意义不同,作用域关注对变量要在哪里查询、怎么查询,而上下文关注的是代码执行流,随着代码的执行而生成、销毁。
  • 创建时间不同,作用域在定义时被确定,而上下文在实行时才被确定。JavaScript采用的是词法作用域规则,也就是说代码写在哪里,作用域就在哪里生成,但是上下文明显并不是由写代码确定的。以函数举例,函数作用域会在声明函数时被创建,但是函数上下文是在函数被调用时才会创建。
  • 可变性不同,作用域一般会保持不变,而执行上下文会随着代码执行流变化而变化。
  1. 什么是作用域链?

作用域链是一个包含指针的列表,每个指针指向一个上下文中的变量对象,这也间接说明了为什么可以把变量对象看成作用域的体现。

上下文中的代码在执行时,会创建一个作用域链,而作用域链的作用就是决定各级上下文访问变量和函数的顺序,简单来说就是查询某个变量时应该遵循什么样的查询顺序。

当代码执行流需要一个变量时,就会沿着作用域链规定的查询顺序查询,这个查询顺序是沿着作用域链从前往后的,因此当前上下文的变量对象永远在作用域链的最前端,全局上下文的变量对象永远在最尾端,即要查找某个变量,先从当前变量对象开始找,找不到就继续往后找,直到全局上下文中的变量对象。

在函数中,作用域链体现在函数的[[Scopes]]特性里。需要注意的是,在声明函数时[[Scopes]]就会被创建,并预装载全局变量对象,在调用函数时再通过复制[[Scopes]]来创建作用域链。