实例详解JavaScript静态作用域与动态作用域

听雨眠
听雨眠
发布时间:2026-10-16| 5人浏览过
原创

JavaScript 采用静态作用域(词法作用域),函数的作用域在定义时即已确定。本文通过概念辨析与三个代码习题,详细演示变量在嵌套作用域中的查找过程,帮助读者掌握变量查找规则,准确预判代码执行结果。

核心概念:静态与动态作用域

在深入代码之前,需要明确两个关键概念:

  • 作用域:一套管理引擎如何根据标识符名称进行变量查找的规则。简单来说,它规定了变量的可见性范围。
  • 静态作用域(词法作用域):函数的作用域在函数定义的时候就已经决定了。变量的查找路径取决于代码编写时的文本结构。
  • 动态作用域:函数的作用域在函数调用时才决定。变量的查找路径取决于运行时函数的调用栈。

JavaScript 遵循的是静态作用域原则。这意味着无论函数在哪里被调用,它的作用域只由函数定义所处的位置决定。

直观对比:一段代码的两种解读

通过以下代码示例,可以清晰看到两种作用域在行为上的巨大差异:

var val = 1;
function test() {
    console.log(val);
}
function bar() {
    var val = 2;
    test();
}

bar();
// 结果是???

代码逻辑如下:

  • 定义全局变量 val = 1。
  • 声明函数 test,用于打印 val。
  • 声明函数 bar,内部定义局部变量 val = 2 并调用 test()。
  • 执行 bar()。

静态作用域的查找过程

当执行 test 函数时:

  1. 首先在 test 函数内部查找 val,未找到。
  2. 沿函数定义的位置向外层查找,进入全局作用域。
  3. 在全局作用域中找到 val = 1。
  4. 结果:输出 1。

关键点:查找始终从定义处开始,逐级向外,不受调用位置影响。

动态作用域的查找过程

如果 JavaScript 支持动态作用域:

  1. 当执行 test 时,首先查内部,无。
  2. 转而查看调用者的作用域,即 bar 函数的作用域。
  3. 在 bar 中找到了 val = 2。
  4. 结果:输出 2。

实战习题:巩固静态作用域思维

理解静态作用域的核心在于:不要看函数在哪里被调用,要看函数在哪里被定义。以下通过三道习题进行验证。

习题一:跨层级定义的函数

var a = 1
function fn1(){
    function fn3(){
        var a = 4
        fn2()
    }
    var a = 2
    return fn3
}
function fn2(){
    console.log(a)
}
var fn = fn1()
fn()

分析:

  • fn1 返回 fn3,执行时进入 fn3 内部,定义 a = 4。
  • fn3 调用 fn2。
  • 关键判断:fn2 是在全局定义的,而非在 fn1 或 fn3 内部。
  • 因此,fn2 的作用域链不包含 fn1 和 fn3 的局部变量。
  • fn2 找不到自己的 a,向上查找至全局作用域,找到 a = 1。
  • 结果:输出 1。

习题二:嵌套定义的函数

var a = 1
function fn1(){
    function fn2(){
        console.log(a)
    }
    function fn3(){
        var a = 4
        fn2()
    }
    var a = 2
    return fn3
}
var fn = fn1()
fn()

分析:

  • fn2 是在 fn1 内部定义的。
  • 执行流程:全局执行 fn1() → 返回 fn3 → 执行 fn3() → fn3 调用 fn2()。
  • 当 fn2 寻找 a 时,它先查自身(无),然后查其定义处的外层,即 fn1。
  • 在 fn1 中找到了 var a = 2。
  • 结果:输出 2。

注意:虽然调用发生在 fn3 中,但 fn2 不关心 fn3,因为它定义在 fn1 中。

习题三:定义顺序与赋值时机

var a = 1;
function fn1(){
    function fn3(){
        function fn2(){
            console.log(a)
        }
        var a;
        fn2()
        a = 4
    }
    var a = 2
    return fn3
}
var fn = fn1()
fn()

分析:

  • fn2 定义在 fn3 内部。
  • 执行到 fn2() 时,fn3 内部有 var a;(变量提升,值为 undefined)。
  • fn2 查找 a,在其定义处的直接外层 fn3 中找到 a。
  • 此时 fn2() 已经执行,但后面的 a = 4 尚未运行。
  • 结果:输出 undefined。

总结

掌握 JavaScript 静态作用域只需记住一条铁律:函数定义的位置决定了它的作用域。在做题或排查作用域问题时,请沿着代码编写的文本结构逐层向上回溯,而不是跟随函数的调用链条。遇到题目时,务必先画出函数的定义嵌套关系,再判断变量查找路径,即可准确得出结果。

以上就是JavaScript静态作用域和动态作用域的详细内容,更多关于JavaScript作用域链和词法作用机的资料请关注本站其它相关文章!

相关标签:

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。