一道题目加强作用域链的理解

65 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第15天,点击查看活动详情

前言

今天没有写博客没有什么思路,于是决定去刷下js题目,做一个题目解析.

错题如下:

image.png 选项如下:

image.png

1.错误思路

  • (1)分析结构:
  • 一共三行代码
  • 第一行声明一个变量
  • 第二行声明一个函数
  • 第三行调用前面声明的函数
  • (2)分析考官意图,题目考察点
  • 考察对作用域的理解
  • 全局作用域全局有效,局部作用域函数内有效,块级作用域,块内有效
  • 考察变量的查找顺序
  • 先在本作用域内查找,查找不到则到上一级作用域内查找
  • (3)得出答案
  • test()会输出a的值
  • 本题中有,两个地方有a的值
  • 一个是全局作用域,一个是块级作用域
  • console.log(a)在函数的局部作用域中,无法向下查找到块级作用域中的a=2
  • 可以向上查找到全局作用域中的var a=1
  • 所以console.log(a)的值为1
  • 选A:1

image.png

2.本题正确思路

  • (1)分析结构:
  • 一共三行代码
  • 第一行声明一个变量
  • 第二行声明一个函数
  • 第三行调用前面声明的函数
  • (2)分析考官意图,题目考察点
  • 考察对作用域的理解
  • 全局作用域全局有效,局部作用域函数内有效,块级作用域,块内有效
  • 考察变量的查找顺序,作用域链
  • 局部内能找到就用局部的找不到采取用外面的
  • 现在本作用域内查找,查找不到则到上一级作用域内查找
  • (3)得出答案
  • test()会输出a的值
  • 本题中有,两个地方有a的值
  • 一个是全局作用域,一个是块级作用域
  • console.log(a)在函数的局部作用域中,本来无法向下查找到块级作用域中的a=2
  • 但是var会变量提升,本质上只分全局和局部,所以var a = 2是局部变量
  • 作用域链先查找当前作用域所以会查找到var a = 2
  • 由于var会变量提升,console.log(a)时a声明了,没有赋值
  • 并且if(false)所以a = 2永远不会赋值
  • 所以console.log(a)的值为undefined
  • 选C:undefined

image.png

image.png

3.实际调试一下

    <script>
        var a = 1;
        function test() {
            console.log(a);
            if (false) {
                var a = 2;
            }
        }
        test();
    </script>

image.png

输出为undefined

如果var换成let会怎样?

    <script>
        let a = 1;
        function test() {
            console.log(a);
            if (false) {
                let a = 2;
            }
        }
        test();
    </script>

image.png

image.png

  • 此时console.log(a)只会访问到全局变量,不会访问到块级变量
  • let 相比var 有严格的作用域限制

4.反思总结

作用域链

一般情况下,变量到创建这个变量作用域中取值。

但是如果在当前作用域中没有查到值,就会向上级作用域去查,直到查到全局作用域,这么一个查找过程形成的链条就叫做作用域链。

  • 在函数内找不到a,就到全局作用域上找

image.png

image.png

var的变量提升

var的变量提升特性,只是提前声明这一步,赋值这一步明没有提前

console.log(a)
var a = 1
//undefined

这是因为var的变量提升特性,使得上面的代码转化为下面写的

var a 
console.log(a)
a = 1
//undefined