认识Javascript中的作用域和作用域链

作用域

只要写过java或者c#等语言的同学来说,相信一定能理解作用域的概念,在作用域的范围中,我们可以使用这个作用域的变量,对这个变量进行各种操作。可是,当使用Javascript的时候,相信很多的同学都会遇到迷惑的时候。

例如,我们看一个常用并经典的案例。

var name = '张三';

function fun() {
    console.log(name);
    var name = '李四';
}
fun()

对于初识javascript的同学来说可能会认为打印的是“张三”,不过我们惊奇的发现打印的是“undefined”,下面我们来分析分析为什么会出现这样的情况。

首先,我们需要认识三个概念:全局变量、局部变量以及变量提升

全局变量

在全局定义的变量为全局变量,在这个作用环境中的所有函数对象都是可以调用到全部变量。

局部变量

顾名思义,局部变量即定义在函数内部的变量。他的作用环境局限在变量所在的局部环境中。

变量提升

在javascript中,函数和变量声明都会被提升到函数的顶部。通俗的来说就是我们可以先使用变量,然后再声明函数。

接下来,我们看看下面几个例子:

例1:

var name = "张三"
function fun() {
    console.log(name);
}
fun()

显而易见,这次我们的打印结果是  “张三”。

现在我们看第二个例子:

例2:

var name = "张三"
function fun() {
    console.log(name);
}
fun()

这次的结果同样是显而易见的,打印了 “张三”。

上面两个例子我们认识了全局变量和局部变量,现在我们再看看第三个例子。

例3:

function fun() {
    console.log(name)
    var name = "李四";
    console.log(name);
}
fun()

这里就需要我们用到变量提升的概念,上面我们提到,javascript对函数和变量声明提升到函数头部,所以在执行第一次打印之前,name这个变量已经被环境帮我们声明了,但是环境并不会帮我们赋值,所以,第一次会打印undefined,然后,第二次打印“李四”。

上面的程序我们换一种写法或许更好理解。

function fun() {
    var name = undefined;
    console.log(name)
    name = "李四";
    console.log(name);
}
fun()

现在我们就可以来理解下最开始说的这个例子了。

var name = '张三';

function fun() {
    console.log(name);
    var name = '李四';
}
fun()

1. 在全部环境中定义了全局变量 name="张三";

2. 在局部环境中定义了name=“李四”,所以局部变量和全局变量名字相同的时候,会优先获取局部变量的值;

3. 由于我们打印name变量是在定义name之前,所以,根据变量提升的特性,所以这里我们会打印 undefined。

相信通过前面几个例子,我们对作用域已经有了一些了解,下面就对作用域进行一下总结。

概念:作用域是一种规则,是 javascript中所有可访问的变量的集合(函数,对象都是变量)。

作用:我们通过作用域可以访问权限内的所有变量,并进行相应操作。

作用域链

对于理解了javascript中的作用域之后,作用域链就是一个比较容易理解的概念。同样,我们也通过一个例子来看。

var age = 18;

function a() {
    var sex = 'sex';

    b();
    function b() {
        var color = 'green';
        
        console.log({age, sex, color})
    }
}

a();

相信大家都能一样看出这段程序的输出结果是{age: 18, sex: "sex", color: "green"},虽然程序简单,不过却是我们理解作用域链的一个好例子。

我们再输出的时候会打印age,sex,color三个变量。

对于color变量来说,本来就在当前执行函数b的作用域内,所以color变量的寻找路径是b.color;

对于sex变量来说,在执行函数b的作用域中找不到sex变量,所以,他会沿着b函数的作用域链找到函数a的作用域,所以sex变量的寻找路径是 b > a.sex;

对于age变量来说,执行函数b中找不到,沿着作用域链找到a函数的作用域依然没找到,就会一直沿着作用域链找到window环境,在这里找到了变量age,所以age变量的寻找路径是b>a>window.age

通过上一个例子,我们应该可以清楚的认识作用域链是什么样的存在,同样我们也总结一下。

概念:作用域链是作用域的具体实现,通过作用域链可以确定变量被访问的权限。

作用:可以通过作用域链,了解我们在当前执行环境可以访问哪些变量。

浅陋见识,不足之处,请大神指正。

原文地址:https://www.cnblogs.com/heshuaiblog/p/13986401.html