浅谈 JavaScript 中变量和函数声明的提升

521 阅读4分钟

「这是我参与11月更文挑战的第5天,活动详情查看:2021最后一次更文挑战

关于JavaScript 中变量和函数声明的提提升,在面试中可能会被问到而且几率还比较大,这里分享一下对JavaScript 中变量和函数声明的提生的理解

什么是变量作用域

变量的生命周期:JavaScript变量的生命周期很简单,从被声明开始,局部变量会在函数运行后被删除,全局变量会在页面关闭后被删除

局部变量:在JavaScript函数内部声明的变量事局部变量,只能在函数内部访问它,可以在不同的函数中使用名称相同的局部变量。

全局变量:在函数外生命的变量是全局变量,网页上所有脚本和函数都能访问它

我们用代码来理解一下:

变量作用域

我们用代码来理解一下它

//demo();这里也可以使用,但是为了新手能理解我们还是在下面使用
function demo(){
    var a = 123;
    console.log(a);
}
demo();//打印123

如果想全局打印a是打印不到的如下:因为a的作用域仅限于 function demo 想要在全局访问是访问不到的,这也是局部变量在执行完以后被删除后console.log(a)就找不到a的原因

function demo(){
    var a = 123;
    console.log(a);
}
console.log(a); //a is not defined

如果你定义了一个全局a,在第二个script标签里也可以访问

这里有个给大家看个代码

function demo(){
    var a = 123;
    b = 456
    console.log(a,b); 
}
demo();//123 456
console.log(b);//456
console.log(a);//a is not defined

这里b明明在方法里面为什么可以访问到呢,细心的同学可以看到我并没有给b定义var 这里b就会跑到window里面去,console.log(b)就回去window中去找个b 所以是可以找到的 同样window里面也存在了demo方法

没有var定义过的属性可以配置全局属性

<script>
        var var1 = 1;//不可配置全局属性
        var2 = 2; //没有用var定义,可以配置全局属性

        console.log(this.var1); //1
        console.log(window.var1);//1

        delete var1;//false 无法删除
        console.log(var1);//1

        console.log(delete var2); //true
        console.log(var2); //not defined
    </script>

作用域链

这里给大家讲一下关于作用域链的代码

var a = "apple";
var b = "boy";
function demo(){
    var a = "vue";
    console.log(a); //vue
    console.log(b); //boy
}
demo();
console.log(a);//apple

这里是为什么呢,函数里面定义了局部变量a 所以demo里面的log就访问局部变量里面的a:vue 但是没有找到b就会去访问全局变量的b:boy, 而外部的log(a)可以直接访问全局的a:apple

声明提升

用一段代码讲解

var a = "apple";
function demo(){
    console.log(a); //undefined
    var a = "angle"//局部变量
    console.log(a);//angle
}
demo();

为什么会出现这中情况呢 这是因为声明提升,我们肉眼是看不到JavaScript的变量提升的 ,我们把它模拟出来

var a = "apple";
function demo(){
    var a;
    console.log(a);
    a = "angle"
    console.log(a);
}
demo();

这就是变量提升后的样子,显而易见,在局部里第一个log(a)找到局部的var a 但是没有赋值所以是undefined,第二个就可以找到a = "angle"

有变量提升自然就有函数提升,我们也用代码来理解一下

var a = "apple";
function demo(){
    console.log(a);//undefined
    var a = "angle";
    console.log(ss()); //angle
    function ss(){
        return a
    }
}
demo();

为什么会出现这种情况,也是因为声明提升造成的,而且函数提升会提升到变量之前,在JavaScript预解析中我们得到这样的代码

var a = "apple";
function demo(){
    function ss(){
        return a
    }
    var a;
    console.log(a); //undefined
    a = "angle";
    console.log(ss()); //angle
}
demo();

显而易见的我们可以看到为什么会输出这样的结果


最后用一道题目来讲一下

var b = 'boy';
console.log(b);//boy
function fighting(){
    console.log(a);
    console.log(c);
    if(a === 'apple'){ a= "Alice";}
    else{a = "Ada";}
    console.log(a);
    var a = "Andy";
    middle();
    function middle(){
        console.log(c++);
        var c = 100;
        console.log(++c);
        small();
        function small(){console.log(a);}
    }
    var c = a = 88;
    function bottom(){
        console.log(this.b);
        b="baby";
        console.log(b);
    }
    bottom();
}
fighting();
console.log(b);

相信初学者看到这道题目一定手心发麻,坐立不安,心跳加速,但是我希望大家不要被这道题吓到然后左上角了,因为面试官出的题可能比我这还要变态

首先我们先预解析一下

var b 
b = 'boy';
console.log(b);//boy 1
function fighting(){
    function middle(){
        function small(){console.log(a);} //Andy 7
        var c 
        console.log(c++); //NaN 5
        c = 100;
        console.log(++c); //101 6
        small(); 
    }
    function bottom(){
        console.log(this.b); //boy 8
        b="baby";
        console.log(b); //baby 9
    }
    var a;
    var c = a
    console.log(a); //undefined 2
    console.log(c); //undefined 3
    if(a === 'apple'){ a= "Alice";}
    else{a = "Ada";}
    console.log(a); //Ada 4
    a = "Andy";
    middle();
    c = a = 88;
    bottom();
}
fighting();
console.log(b); //baby //10

之后根据我的注释的打印输出顺序,可以慢慢解出这道题目。

这就是我对于JavaScript中变量和函数声明的提升的理解,希望能帮助到大家