写点什么

谈谈 JavaScript 的作用域及作用域链

  • 2022 年 7 月 15 日
  • 本文字数:2023 字

    阅读完需:约 7 分钟

前言

作用域和作用域链在前端里是比较简单的概念,但往往因为简单而被人忽视,涉及到作用域链产生的 bug 很容易让人摸不着头脑。其实再简单的知识点也有复杂的地方,就像再复杂的概念也有易于理解的点一样。今天大冰块从 作用域变量范围作用域链 这三个方面好好谈一谈 JavaScript 的作用域及作用域链,希望各位同学看完之后能有所收获。

作用域

概念:变量声明后,能够在哪个范围内起作用。

块级作用域

块级作用域: 由花括号组成代码结构的范围 {} ,在花括号里面声明的变量在外部无法访问。其实 JavaScript 是不支持块级作用域的,那么为什么大冰块还要说一下这个呢?多了解一点总是没坏处的,比如面试的时候,别人没说这个,但是你把这个点一提,是不是水平立马就提升了?(手动滑稽)


    if(true){        var num = 100    }    console.log(num) // 100   js可以获取到{}内声明的变量

for(var i = 0; i < 10; i++){ var str = "能访问到我吗" } console.log(str) // 能访问到我吗 js可以获取到{}内声明的变量
复制代码

词法作用域

词法作用域: 也叫函数作用域,因为在 js 里面,只有函数才能形成作用域。也叫静态作用域,因为它的作用域是指在词法分析阶段就确定了,不会改变。动态作用域是在运行时根据程序的流程信息来动态确定的,而不是在写代码时进行静态确定的。而词法作用域是在写代码或者定义时确定的,而动态作用域是在运行时确定的(this 也是!)。词法作用域关注函数在何处声明,而动态作用域关注函数从何处调用。


    function fn(){        var num = 100    }    console.log(num) // num is not defined
复制代码

变量范围

根据作用域把变量分为 3 类

全局变量

在函数外部声明的变量就是全局变量,在任意位置都能够访问到


    var num = 100    function fn(){      console.log(num) // 100    }    console.log(num) // 100
复制代码

局部变量

在函数内部声明的变量就是局部变量,只能在函数内部使用。


    function fn(){        var num = 100    }    console.log(num) // num is not defined
复制代码

自由变量

对于一个函数来说,如果这个变量不是在这个函数内部声明的,但是却使用了这个变量,对于这个函数来说,这个变量就是自由变量


    var a = 100    function fn(){        var b = 200        console.log(a) // 100,对fn函数来说,a是自由变量        console.log(b) // 200    }    fn()
复制代码

作用域和变量的关系

函数的作用域在函数定义的时候就已经确定下来了,函数定义的时候就已经确定下来了,函数定义的时候就已经确定下来了,重要事情说三遍。也就是说,函数作用域和函数在哪调用是没有关系的,以及函数如何被调用都是没有关系的。和 this 不同,this 是在函数被调用的时候才确定,函数是如何被调用的。函数作用域的查找是如何查找到呢?


1. 如果变量是在函数内部声明的,直接在当前作用域内就查找到了2. 如果变量是自由变量,去创建这个函数的作用域中去查找
复制代码


好了,说了这么多,出一道题考考你,请看下面的题目:


    var num = 123    function f1() {      console.log(num)    }
function f2(){ var num = 456 f1() } f2() // 这里会打印啥?
复制代码


各位同学,请把你的答案贴在评论区。

作用域链

作用域链:函数能够形成作用域,如果函数被嵌套在另一个函数中,嵌套的函数也有自己的作用域,从这个函数的作用域往外形成的一条链, 这个链叫做作用域链。例如:


  function outer(){      function inner(){          function fn(){          }      }  }
复制代码


上面代码中:函数 outer 的作用域链: outer 作用域 ==> 全局作用域函数 inner 的作用域链: inner 作用域 ==> outer 作用域 ==> 全局作用域 fn 的作用域链: fn 作用域 ==> inner 作用域 ==> outer 作用域 ==> 全局作用域

作用域链: 变量搜索规则:

1. 首先在当前作用域内查找是否有声明该变量,如果有,直接返回。2. 如果没有,向上一级作用域查找,,如果有,直接返回。3. 如果没有,沿着作用域链进行查找,直到全局作用域,如果有,直接返回。4. 如果一直找到最后还是没有,就会报错not defined5. 在哪一层找到了该变量的声明,直接返回结果,就不继续查找。
复制代码


好了,下面再出一道题考考大家:


    var num = 1000    function outer(){        var num = 999        function inner(){            var num = 888            function fn(){                var num = 777                console.log(num)            }            fn()        }        inner()    }    outer()
复制代码


各位同学,请把再次把你的答案贴在评论区。

后记

在平时写代码的过程中,如果作用域和作用域链如果理解的不透彻,很容易产生 bug。相信通过大冰块从作用域,变量范围,作用域链这几个方面的详细解读,你一定对作用域和作用域链有了更透彻的理解。如果本篇文章由帮助到你,希望能点赞支持一下,不枉我熬夜淦完这篇文章。如果有错误也欢迎指出交流。感谢阅读~

发布于: 刚刚阅读数: 2
用户头像

还未添加个人签名 2022.07.01 加入

还未添加个人简介

评论

发布
暂无评论
谈谈JavaScript的作用域及作用域链_7月月更_南极一块修炼千年的大冰块_InfoQ写作社区