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

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

相关推荐
passerby606119 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了19 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅20 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅20 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅20 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment20 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅21 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊21 小时前
jwt介绍
前端
爱敲代码的小鱼21 小时前
AJAX(异步交互的技术来实现从服务端中获取数据):
前端·javascript·ajax
Cobyte21 小时前
AI全栈实战:使用 Python+LangChain+Vue3 构建一个 LLM 聊天应用
前端·后端·aigc