作用域
词法作用域与变量作用域是JavaScript这门语言中模块化层次的全部体现
词法作用域是基于静态词法分析的
所谓的变量作用域既是静态的,也是动态与静态之间的一座桥梁
从实现的方式来看,一些书籍中称纯粹的词法作用域实现为“静态作用域”,而与代码执行期效果相关的变量作用域则被称为“动态作用域”
词法作用域
一般来说,编程语言中的函数都要解决其变量或成员的可见性问题。而这个可见性的区间,被称为作用域 scope
,而当这个域是由静态词法分析而得出的时候,它就被称为词法作用域
具体点看,作用域 scope
是指程序源代码中定义变量的区域。规定了如何查找变量,也就是确定当前执行代码对变量的访问权限。
编程语言中的作用域可以简单分为两种:
- 静态作用域
static scope
(词法作用域lexical scope
) - 动态作用域
dynamic scope
二者的区别在于定义函数的作用域的时机。静态作用域在函数声明时确定,动态作用域在函数执行时确定
很巧的是,JavaScript用的是静态作用域,即函数的作用域在函数声明的时候就已经被确定了,与函数的调用位置无关。
同时,动态作用域在JavaScript中也有对应的表现,即this
机制。
函数作用域与块级作用域
JavaScript使用静态作用域,在JavaScript中通常可以继续细分为函数作用域和块级作用域,但二者不是对立关系
- 函数作用域:由函数声明定义,在函数内声明的所有变量在函数体内始终是可见的,可以在整个函数的范围内使用及复用。每有一个函数就会有一个对应的作用域。全局与模块也可以理解为一个函数。
- 块级作用域:由花括号
{}
标识的形式分块,存在于在函数中。
在一些类C语言中,花括号内的每一段代码都具有各自的作用域,而且用的都是块级作用域,而且变量在声明它们的代码段之外是不可兼得。而在早期的JavaScript中,没有块级作用域这个概念,取而代之地使用了函数作用域。
但实践证明,块级作用域真香,var
是真的垃圾,然后在es6补上了块级作用域的实现。
es6新增了 let/const
来声明仅块级作用域可见的变量
这里可以简单理解为 var
声明的变量只能存在函数作用域中;而 let/const
可以在块级作用域中定义变量,即相关变量只能在对应的块级作用域中使用,不会 “逸出” 到块级作用域所在的函数作用域中。
if (true) {
var varA = "varA";
let letA = "letA";
for (let i = 0; i < 1; i++) {
var varB = "varB";
let letB = "letB";
}
}
console.log(varA, varB); // varA varB
console.log(letA, letB); // ReferenceError: letA is not defined
具体实现细节则需要通过词法环境来解释,下一节《环境记录》会对其进行尽可能详尽的解释
作用域链
在ES3的规范中,存在作用域链 scope chain
的概念,这个内部属性包含了函数被创建的作用域中对象的集合,这个集合被称为函数的作用域链。
在ES5中这个概念被词法环境 Lexical Environment
取代
在《红宝书第四版》《权威指南第七版》中对于作用域中变量的引用的解释使用的仍然是作用域链、VO / AO 这一套,在《忍者秘籍第二版》《语言精髓第三版》里面使用的则是词法环境。
变量作用域
词法作用域的提出主要是ECMAScript5的主要成就。ECMA趁机将诸多与变量相关的JavaScript历史特性,统统归纳到“变量作用域”这一概念集合下,形成了独特的“两种作用域”规范体系。
历史中,变量作用域又叫变量的可见性
早期JavaScript的变量作用域,只有所谓的全局变量、局部变量两种,并且有且仅有函数与全局环境支持变量作用域。而从ES6开始,模块也是支持变量作用域的。
也因为变量作用域是个历史产物的概念集合,所以块中是不存在独立的变量作用域的。
在严格模式下,函数和模块的变量作用域是作为词法作用域的一部分来实现的。全局的变量作用域是映射到全局对象的属性上的,并非一个独立的作用域/环境
总的来说,JavaScript中的作用域可以简单的理解为
- 词法作用域:全局、函数、模块、块都与之相关联。
- 变量作用域:则是全局、函数和模块才会有的。且在严格模式下,变量作用域是词法作用域的一部分。
- 函数作用域:通常指同时拥有词法作用域和变量作用域中的一个整体
而这些都只是抽象的概念,下一节会通过作用域的具体实现形式来分析。
参考资料
《JavaScript语言精髓与编程实践》(第三版)
《JavaScript高级程序设计》(第四版)
《JavaScript权威指南》(第七版)
《JavaScript忍者秘籍》(第二版)
Day14 - 词法作用域、块级作用域、作用域链、静态动态作用域
最后
作者水平有限,如果有错误或者不严谨的地方,请务必指出,十分感谢!!!