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. 考虑变量表示的优先级。

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

相关推荐
人工智能训练3 小时前
【极速部署】Ubuntu24.04+CUDA13.0 玩转 VLLM 0.15.0:预编译 Wheel 包 GPU 版安装全攻略
运维·前端·人工智能·python·ai编程·cuda·vllm
会跑的葫芦怪4 小时前
若依Vue 项目多子路径配置
前端·javascript·vue.js
xiaoqi9225 小时前
React Native鸿蒙跨平台如何进行狗狗领养中心,实现基于唯一标识的事件透传方式是移动端列表开发的通用规范
javascript·react native·react.js·ecmascript·harmonyos
jin1233225 小时前
React Native鸿蒙跨平台剧本杀组队消息与快捷入口组件,包含消息列表展示、快捷入口管理、快捷操作触发和消息详情预览四大核心功能
javascript·react native·react.js·ecmascript·harmonyos
烬头88217 小时前
React Native鸿蒙跨平台实现二维码联系人APP(QRCodeContactApp)
javascript·react native·react.js·ecmascript·harmonyos
pas1367 小时前
40-mini-vue 实现三种联合类型
前端·javascript·vue.js
摇滚侠7 小时前
2 小时快速入门 ES6 基础视频教程
前端·ecmascript·es6
2601_949833397 小时前
flutter_for_openharmony口腔护理app实战+预约管理实现
android·javascript·flutter
珑墨7 小时前
【Turbo】使用介绍
前端
军军君018 小时前
Three.js基础功能学习十三:太阳系实例上
前端·javascript·vue.js·学习·3d·前端框架·three