JS之深入理解作用域和作用域链

每种语言,都需要细嚼慢咽,才能发现它的美妙!在JS中,JS有两条很重要的链——原型链和作用域链

接下来一起来学习作用域和作用域链的相关知识~

1)作用域

  • 什么是作用域?
    • 我个人的理解就是该变量能作用的范围
  • 分类:
    • 全局作用域:在全局中声明的变量(全局变量)所在的环境
    • 函数作用域:函数内部声明的变量(局部变量)所在的环境

这里需要注意的是,函数内的变量可以访问所在的外部变量,但是外部的变量不能访问函数的内部变量(这里要通过闭包来间接访问)

2)在介绍分析作用域中的变量前,还需要先来理解一下var声明

  • var声明的特点
    • 全局中,通过var声明的变量,会直接成为window对象的属性,故可以通过window.xxx来访问该属性
    • var声明的变量会被提升到全局或者函数的最顶部(var的提升机制)
var a=1;
console.log(a);//1
console.log(window.a);//1
function boost(){
    console.log(a);//1
    var a=1;
}

由于变量的提升机制,所以不会报错,这里实际上就进行了如下的等价操作:

function boost(){
    var a=1;
    console.log(a);
}

注意:对于函数内的一个变量,如果有使用var声明,则作为该函数内的局部变量,如果没有var声明,就只是一个赋值语句,并不一定是作为全局变量

下面通过一个例子来说明:

 function t1(){
        var d;
        function t2(){
            d=5;//这里在t2中没有找到,在t1中找到,故d=5,但由于此时存在函数作用域,故在全局中没有这个变量
            e=6; //在t2和t1函数中都没有找到,所以这里相当于在全局中声明了window.e=6;
        }
        t2();
    }
    t1();
    console.log(e);//6
    console.log(window.d);//undefined
    console.log(d);//报错,d is not defined

这里需要注意的是:

以window.xxx引用全局变量,寻找不到,作为某个属性不存在,返回undefined

直接以xxx引用某个变量,寻找不到,则是报xxx is not defined错误

3)关于作用域的应用,最常用的是判断输出的值是什么。在此之前,还需要涉及到一个词法分析过程。即在运行JS代码的过程中,有一个词法分析过程和执行过程。在判断时,也是有一定的套路的,以下是借鉴了别人的方法:

  • 词法分析过程(分析3样东西)
    • 分析函数声明
    • 在分析变量声明
    • 先分析参数
    • 具体步骤:
      • 第一步:函数运行前的一瞬间,生成Active Object(活动对象),以下称为AO
      • 第二步:分析参数
        • 1)把声明的参数,形成AO的属性,值全是undefined
        • 2)接受参数
      • 第三步:分析变量声明,如:var age,如果AO上还没有age属性,则添加AO属性,值为undefined,如果AO上已有age属性,则不做任何影响
      • 第四步:分析函数声明,如:function foo(){},则把函数赋给AO.foo属性,如果此前foo属性已存在,则被无情覆盖
  • 执行过程,按照从上到下的顺序执行

下面举个例子来详细说明:

 function a(b){
        alert(b);
        function b(){
            alert(b);
        }
        b();
    }
    a(1);
    /*
    词法分析过程:
    0:生成一个AO={}
    1:
        1.1分析参数,AO={b:undefined}
        1.2接收参数,AO={b:1}
    2:分析变量,无,跳过
    3:分析函数,有,AO={b:function(){alert(b)}}

    执行过程:
    79行:alert(b);//输出一个函数
    83行调用,执行81行,输出一个函数

     */

如果函数里再嵌套函数,则继续按照上面的步骤继续分析

注意:对于函数的分析是从外到内,对于变量作用域的寻找是从里到外

在变量寻找的过程中,变量从包裹该变量的函数从内往外寻找的过程中,就形成了一条作用域链,一直沿着这条作用域链寻找,如果没有发现该变量,则值为返回值为undefined(该变量必须先声明)

猜你喜欢

转载自blog.csdn.net/tozeroblog/article/details/82592973