JavaScript高级之变量声明提升和函数声明提升

Posted 二木成林

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JavaScript高级之变量声明提升和函数声明提升相关的知识,希望对你有一定的参考价值。

变量声明提升

通过var定义(声明)的变量,在定义语句之前就可以访问到,而值为undefined

<script type="text/javascript">
    console.log(a);// undefined
    var a = 5;
</script>

因为实际上是这样处理的:

<script type="text/javascript">
		var a;
    console.log(a);// undefined
    a = 5;
</script>

或者在局部变量提升的情况:

<script type="text/javascript">
    var a = 5;

    function fn() 
        console.log(a);// undefined
        var a = 10;
    
    fn();
</script>

实际上是这样处理的:

<script type="text/javascript">
    var a = 5;

    function fn() 
        var a;
        console.log(a);// undefined
        a = 10;
    
    fn();
</script>

注意,如果局部变量和全局变量同名,那么局部变量的优先级更高。

这就是提升,把变量的声明提升到了作用域的最前端。

函数声明提升

通过function声明的函数,在函数定义之前就可以直接调用,值就是函数对象。

<script type="text/javascript">
    // 在函数定义之前就可以调用函数
    hello();

    function hello() 
        console.log('hello world');
    
</script>

来看看这个情况:

<script type="text/javascript">
    var a = true;
    hello();

    function hello() 
        if (a) 
            var a = 10;
        
        console.log(a);// undefined
    
</script>

实际上是按照下面这样来进行处理的,所以最终的结果为undefined:

<script type="text/javascript">
    function hello() 
        var a;
        if (a) 
            a = 10;
        
        console.log(a);// undefined
    

    var a;
    a = true;
    hello();
</script>

因为JavaScript没有块级作用域,所以if语句中的var a=10中的var a;会提升到函数作用域的顶端,并且局部变量和全局变量同名,因为局部变量的优先级更高,所以a为undefined,在if判断中为false,所以打印结果为undefined。

但需要注意的是,函数声明(即function fn() )会被提升,而函数表达式(即var fn = function () )却不会提升,如下:

<script type="text/javascript">
    fn();

    var fn = function () 
        console.log('hello world');
    
</script>

发现它报错了:Uncaught TypeError: fn is not a function。因为就是变量提升,而这个变量还没有赋为函数:

<script type="text/javascript">
    var fn;
    fn();

    fn = function () 
        console.log('hello world');
    
</script>

注意:函数提升的优先级比变量提升优先级高

<script type="text/javascript">
    // 证明方式一
    function a() 

    
    var a;
    console.log(typeof a) // 'function'

    // 证明方式二
    f1();// 1
    function f1() 
        console.log('1');
    
    var f1 = function () 
        console.log('2');
    
</script>

看看下面这个复杂的情况:

<script type="text/javascript">
    var c = 1;
    function c(c) 
        console.log(c);
        var c = 3;
    
    c(2); // 报错 Uncaught TypeError: c is not a function
</script>

发现报错Uncaught TypeError: c is not a function,如果我们在c(2);之前打印c的值(即console.log(c);)发现结果为1。它等价于如下:

<script type="text/javascript">
    function c(c) 
        var c;
        console.log(c);
        c = 3;
    

    var c;
    c = 1;
    c(2);
</script>

因为发生了变量声明提升和函数声明提升,它们同时出现在代码中,那么函数声明会优先提升,而又遇到一个需要提升的同名变量声明,但会被忽略,我们可以在下面的打印中看出结果:

<script type="text/javascript">
    function c(c) 
        var c;
        console.log(c);
        c = 3;
    

    console.log(c);// function c(c)
    var c;// 会被忽略
    console.log(c);// function c(c)
    c = 1;
    console.log(c);// 1
    c(2);// Uncaught TypeError: c is not a function
</script>

总结

  • 在ES6之前,JavaScript没有块级作用域(即),只有全局作用域和函数作用域。
  • 在函数作用域中,局部变量的优先级比全局变量的优先级高。
  • 无论变量声明还是函数声明都会在执行之前处理,进行声明提升,提升到各自作用域的最前端。
  • 函数声明会被提升,但是函数表达式也不会被提升。
  • 如果同时存在函数声明提升和变量声明提升,那么函数声明提升的优先级更高。
  • 如果存在多个函数声明,则出现在后面的函数声明会覆盖前面的。

以上是关于JavaScript高级之变量声明提升和函数声明提升的主要内容,如果未能解决你的问题,请参考以下文章

JavaScript之函数

JavaScript高级之ECMAScript 6 新特性

JavaScript之变量提升

JS-作用域

JavaScript 变量声明提升

JavaScript系列文章:变量提升和函数提升