JS学习——作用域解析

前言

作用域大家都不陌生,正所谓面试造火箭,现实拧螺丝,面试时我们会碰到各种类型的题,这些题跟作用域的特性息息相关,这种体现理论的题最容易犯错,往往看了解析会恍然大悟。本节我们就来学习一下作用域的特征。

作用域特征

作用域包含几个特征,掌握了它们,相关面试题也就很简单了:

  • 块级作用域。块级作用域简单来说就是{}里面的区域,es6中的let与const声明的变量就是块级作用域,块级作用域的变量只会在块级里面生效。
js 复制代码
   function a(){
      let b = 1
    }
    console.log(b) //b is not defined

b是块级作用域,在块级外就是未定义。除了let、const声明出来的变量,在js中只有函数才有块级作用域。上述例子中我们用let定义了b变量,如果换成var呢?

js 复制代码
    function a(){
      var b = 1
    }
    console.log(b) //b is not defined

依旧是未定义的,因为b是在a函数里面的定义的,它就是块级作用域。除此之外在其他地方如果用var它就是全局的。

js 复制代码
   if(true){
      var a = 0
    }
    console.log(a) //0

这时候把var换成let或const,那么a肯定就是未定义的,因为这两个声明出来的变量是块级的。三者之间的区别我们要牢牢掌握的。

  • 作用域链。函数中的变量值如果当前函数未定义,会去上一层函数中去寻找,直至找到或者到script全局,这就是作用域链,作用链讲究就近原则 ,并且只有从内往外找,外部不能访问内部的变量
js 复制代码
    function a(){
      var c = 1
      function b(){
        var d = 2
        console.log(c) // 1
      }
      b()
      console.log(d) // d is not defined
    }
    a()
  • 全局变量。如果一个变量直接赋值,没有声明那么它就是全局变量,有着全局作用域,全局变量就是在window上面的。
js 复制代码
   (function () {
        var a = b = 1;
      })();
      // console.lg(a); // a is not defined
      console.log(b); // 1

b是直接赋值的,所以b是全局变量,相当于window.b,而a是在函数中定义的,所以a是块级作用域,在函数外打印不出,b却可以。

  • 变量提升。用var声明的变量,会把声明放到最顶层,这种机制被称为变量提升,注意let、const是没有变量提升的。
js 复制代码
      console.log(a) // undefined
      var a = 1
      console.log(b) //Cannot access 'b' before initialization
      let b = 2

a用var声明的,var就会放到前面,所以打印undefined而没有报错,但是let就会直接报错。

实例

熟悉以上特性,碰到相关面试题做出来就不在话下,下面我们实战解析,看下具体的,面试题:

  • 第一道:
js 复制代码
   function a() {
        var b = 1;
        function c() {
          console.log(b);
          var b = 2;
          console.log(b);
        }
        c();
        console.log(b);
      }
      a();

打印出来的依次是undefined、2、1。这道题考察了变量提升、作用域链,在c函数中变量b进行了声明提升,所以第一次打印b为undefined,后面赋值为2,而a函数中,有声明的b,根据作用域链打印出来为1。

  • 第二道:
js 复制代码
   function a(b) {
        console.log(b);
        function b() {}
        console.log(b);
      }
    a(2);

这道题打印出来的是两个b函数,该题考查了变量的优先级,我们在函数中声明了b函数,声明函数提升,所以函数中打印的都是b函数。下面我们将b赋值为函数又会打印什么呢?

js 复制代码
   function a(b) {
        console.log(b);
        var b = function () {};
        console.log(b);
      }
      a(2);

答案是2,赋值的函数,注意这次我们是将b进行赋值,而不是直接声明b函数,那为什么第一个不是undefined呢?因为第一个b表示了形参 ,当我们直接a(2),此时b就是实参的值。通过这两个例子我们知道变量是有优先级,具体的优先级为:
变量声明>函数声明>参数>变量提升

在函数中碰到相同的变量,我们要根据优先级知道它表示的是哪个值。

总结

作用域考查的就是我们的基础,面试中碰到了作用域相关的题,我们可以按照以下步骤去分析:

  1. 变量是否为全局变量、是否在函数内声明。

  2. 找到变量作用域链。

  3. 考虑变量表示的优先级。

    通过以上分析,大概率就能得到正确的答案啦。

相关推荐
轻口味32 分钟前
【每日学点鸿蒙知识】AVCodec、SmartPerf工具、web组件加载、监听键盘的显示隐藏、Asset Store Kit
前端·华为·harmonyos
alikami35 分钟前
【若依】用 post 请求传 json 格式的数据下载文件
前端·javascript·json
wakangda1 小时前
React Native 集成原生Android功能
javascript·react native·react.js
吃杠碰小鸡1 小时前
lodash常用函数
前端·javascript
emoji1111111 小时前
前端对页面数据进行缓存
开发语言·前端·javascript
泰伦闲鱼1 小时前
nestjs:GET REQUEST 缓存问题
服务器·前端·缓存·node.js·nestjs
m0_748250031 小时前
Web 第一次作业 初探html 使用VSCode工具开发
前端·html
一个处女座的程序猿O(∩_∩)O2 小时前
vue3 如何使用 mounted
前端·javascript·vue.js
m0_748235952 小时前
web复习(三)
前端
User_undefined2 小时前
uniapp Native.js原生arr插件服务发送广播到uniapp页面中
android·javascript·uni-app