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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值