JavaScript之静态作用域与动态作用域

简介: JavaScript之静态作用域与动态作用域

前言


在文章最开始,先学习几个概念:


  • 作用域:《你不知道的js》中指出,作用域是一套规则,这套规则用来管理引擎如何在当前作用域以及嵌套的子作用域中根据标识符名称进行变量查找。简单来说,作用域规定了如何查找变量。
  • 静态作用域:又称词法作用域,函数的作用域在函数定义的时候就决定了,通俗点说就是你在写代码时将变量和块作用域写在哪里决定的。
  • 动态作用域:函数的作用域在函数调用时才决定的。


静态作用域与动态作用域


JavaScript采用的是静态作用域,函数定义的位置就决定了函数的作用域。 具体看一个例子,理解一下什么是静态作用域与动态作用域的区别


var val = 1;
function test() {
    console.log(val);
}
function bar() {
    var val = 2;
    test();
}
bar();
// 结果是???
复制代码


上面代码中:


  • 我们首先定义全局变量 val,赋值为 1
  • 声明一个函数 text,函数的功能是打印 val 这个变量的值
  • 声明一个函数 bar,函数内部定义局部变量 val,赋值为 2;并且函数内部执行 test() 函数
  • 执行 bar() 函数


静态作用域执行过程


当执行 test 函数时,先从 test 函数内部查找是否有变量 val,如果没有,就沿定义函数的位置,查找上一层的代码,查找到全局变量 val ,其值为 1


作用域查找始终从运行时所处的最内层作用域开始查找,逐级向外查找,直到遇见第一个匹配的标识符为止。


无论函数在哪里被调用,无论如何被调用,它的作用域只由函数定义所处的位置决定。


动态作用域执行过程


执行 test 函数,首先从函数内部查询 val 变量,如果没有,就从调用函数的作用域,即 bar 函数的作用域内部查找变量 val,所以打印结果 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()
复制代码


上面代码中:


  • 我们首先定义全局变量 a,赋值为 1
  • 声明一个函数 fn1,函数的内部分别声明了函数 fn3,定义局部变量 a,赋值为 2,返回值为 fn3 函数
  • fn3 函数内部定义局部变量 a,赋值为 4,执行 fn2()
  • 声明函数 fn2, 函数的功能是,打印 a 的值
  • fn 赋值为 fn1() 的返回值
  • 执行 fn() (相当于执行 fn3 函数)


做题之前,一定要理解 静态作用域 的概念。该题 fn2 定义在全局上,当 fn2 中找不到变量 a 时,它会去全局中寻找,与 fn1fn3 毫无关系,打印 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 内部,因此当 fn2 内部没有变量 a 时,它会去 fn1 中寻找,跟函数 fn3 毫无关系,如果 fn1 中寻找不到,会到 fn1 定义的位置的上一层(全局)寻找,直至寻找到第一个匹配的标识符。本题可以在 fn1 中找到变量 a,打印 2


习题三


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 中找不到变量 a 时,会首先去 fn3 中查找,如果还查找不到,会到 fn1 中查找。本题可以在 fn3 中找到变量 a,但由于 fn2() 执行时,a 未赋值,打印 undefined


总结


关于JavaScript 的静态作用域,我们只需要记住一句话:函数定义的位置就决定了函数的作用域,遇到题目时不要被别的代码干扰到。


而且习题二,习题三查找变量的过程,其实本质上就是沿着作用域链在查找,关于作用域链的相关知识,敬请期待下文


JavaScript深入学习专栏目录



相关文章
|
5月前
|
JavaScript 前端开发
js的作用域作用域链
【10月更文挑战第29天】理解JavaScript的作用域和作用域链对于正确理解变量的访问和生命周期、避免变量命名冲突以及编写高质量的JavaScript代码都具有重要意义。在实际开发中,需要合理地利用作用域和作用域链来组织代码结构,提高代码的可读性和可维护性。
|
5月前
|
自然语言处理 JavaScript 前端开发
[JS]作用域的“生产者”——词法作用域
本文介绍了JavaScript中的作用域模型与作用域,包括词法作用域和动态作用域的区别,以及全局作用域、函数作用域和块级作用域的特点。通过具体示例详细解析了变量提升、块级作用域中的暂时性死区等问题,并探讨了如何在循环中使用`var`和`let`的不同效果。最后,介绍了两种可以“欺骗”词法作用域的方法:`eval(str)`和`with(obj)`。文章结合了多位博主的总结,帮助读者更快速、便捷地掌握这些知识点。
61 2
[JS]作用域的“生产者”——词法作用域
|
5月前
|
前端开发 JavaScript 数据处理
CSS 变量的作用域和 JavaScript 变量的作用域有什么不同?
【10月更文挑战第28天】CSS变量和JavaScript变量虽然都有各自的作用域概念,但由于它们所属的语言和应用场景不同,其作用域的定义、范围、覆盖规则以及与其他语言特性的交互方式等方面都存在明显的差异。理解这些差异有助于更好地在Web开发中分别运用它们来实现预期的页面效果和功能逻辑。
107 11
|
5月前
|
JavaScript 前端开发
javascript的作用域
【10月更文挑战第19天javascript的作用域
|
5月前
|
JavaScript 前端开发
如何在 JavaScript 中实现块级作用域?
【10月更文挑战第29天】通过使用 `let`、`const` 关键字、立即执行函数表达式以及模块模式等方法,可以在JavaScript中有效地实现块级作用域,更好地控制变量的生命周期和访问权限,提高代码的可维护性和可读性。
|
6月前
|
JavaScript 前端开发
JavaScript 作用域
JavaScript 作用域是指程序中可访问的变量、对象和函数的集合。它分为函数作用域和局部作用域。函数作用域内的变量仅在函数内部可见,而全局作用域的变量在整个网页中均可访问。局部变量在函数执行完毕后会被销毁,而全局变量则在整个脚本生命周期中都存在。未使用 `var` 关键字声明的变量默认为全局变量。
|
6月前
|
JavaScript 前端开发
js作用域
js作用域
42 1
|
7月前
|
JavaScript 前端开发
js 变量作用域与解构赋值| 22
js 变量作用域与解构赋值| 22
|
7月前
|
缓存 JavaScript 前端开发
了解js基础知识中的作用域和闭包以及闭包的一些应用场景,浅析函数柯里化
该文章详细讲解了JavaScript中的作用域、闭包概念及其应用场景,并简要分析了函数柯里化的使用。
了解js基础知识中的作用域和闭包以及闭包的一些应用场景,浅析函数柯里化
|
7月前
|
JavaScript 前端开发
JavaScript 作用域
JavaScript 作用域
40 9
下一篇
oss创建bucket