JavaScript 使用 词法作用域(又称为静态作用域),这是一种确定变量和函数可访问性的机制。以下是关于 JavaScript 词法作用域的详细说明:
特征:
-
基于代码结构:
- 词法作用域基于源代码的结构来决定变量和函数的可见性。在编写代码时,根据变量和函数的物理位置(即它们在源代码中的位置)来确定它们属于哪个作用域。
-
作用域确定时机:
- 编译阶段:词法作用域在编译阶段(词法分析阶段)就已经确定,这意味着无论函数何时被调用或以何种方式调用,其能够访问的变量和函数都是由其在源代码中的位置决定的。
-
作用域层次:
- 全局作用域:顶层作用域,所有在任何函数外部定义的变量和函数都属于全局作用域,可以在整个程序中访问。
- 局部作用域:由函数创建。每个函数有自己的作用域,其中定义的变量和函数只能在其内部以及其嵌套的作用域中访问。
-
作用域链:
-
查找规则:
- 从内到外:当在当前作用域中查找变量或函数时,如果找不到,则会沿着作用域链向上级作用域(如外层函数、直至全局作用域)逐级查找,直到找到目标变量或函数或者到达全局作用域为止。
-
作用域链构建:
- 每个函数在被调用时,都会创建一个执行上下文,其中包含了作用域链。作用域链是一个对象列表,按照函数定义时的词法层级顺序排列,最前端是当前作用域(活动对象,
AO或LexicalEnvironment),之后是其外层作用域,直至全局作用域(全局对象,GO或GlobalLexicalEnvironment)。
- 每个函数在被调用时,都会创建一个执行上下文,其中包含了作用域链。作用域链是一个对象列表,按照函数定义时的词法层级顺序排列,最前端是当前作用域(活动对象,
-
-
闭包:
- 概念:当一个函数可以访问并操作其外部作用域(包括其父函数作用域及更外层作用域,直至全局作用域)中的变量时,即使在其外部作用域已经结束执行后,这种现象被称为闭包。
- 应用:闭包使得函数可以“记住”并操作其词法作用域内的状态,常用于实现数据隐藏、模块化、异步控制、缓存计算结果等场景。
-
示例说明:
javascript
// 全局作用域
var globalVar = "global";
function outer() {
// 外部函数作用域
var outerVar = "outer";
function inner() {
// 内部函数作用域
var innerVar = "inner";
console.log(innerVar); // "inner"
console.log(outerVar); // "outer"
console.log(globalVar); // "global"
}
inner();
}
outer();
在此例中:
inner函数可以访问其内部定义的innerVar。- 它还可以访问外部
outer函数作用域中的outerVar,因为outer是inner的词法父作用域。 - 最后,
inner能够访问全局作用域中的globalVar,这是作用域链的最顶端。
结论
JavaScript 词法作用域基于代码的静态结构来确定变量和函数的访问权限。理解词法作用域对于编写清晰、无意外副作用的 JavaScript 代码至关重要,它有助于避免变量遮蔽、理解闭包行为,并有效地利用作用域进行信息隐藏和资源管理。