美文网首页JavaScript 基础与提高
JavaScript 坑与技巧:变量提升机制

JavaScript 坑与技巧:变量提升机制

作者: soojade | 来源:发表于2019-04-05 13:47 被阅读3次

    变量提升,即程序在自上而下执行之前,在本作用域内,由varfunction声明的变量或函数,会被提升到最顶端,之后才开始按代码自上而下的顺序执行。变量的默认初始值为undefined,而函数则是函数声明的字符串。如下所示:

    console.log(a);
    console.log(fn);
    
    var a = 10;
     function fn() {
        console.log(fn);
     }
    

    结果如下:
    undefined
    ƒ fn() {
       console.log(fn);
    }

    示例一:

    console.log(a);
    console.log(b);
    
    var a = b = 10; 
    

    结果如下:
    undefined
    Uncaught ReferenceError: b is not defined

    这里的 b 并不是用 var 声明的,所以没有被提升。

    示例二:

    console.log(a);
    console.log(b);
    
    var a , b = 10;
    

    结果如下:
    undefined
    undefined

    这里的 b 相当于使用var声明

    示例三:

    console.log(a);
    console.log(b);
    
    let a , b = 10;
    

    结果如下:
    Uncaught ReferenceError: a is not defined

    let const class都不会有变量提升

    示例四:

    console.log(a);
    console.log(b);
    
    let a = b = 10;
    

    结果如下:
    Uncaught ReferenceError: a is not defined

    由于let没有变量提升,所以报错--未被定义

    示例五:

    console.log(a);
    console.log(b);
    
    var a = 10;
    b = 10;
    

    结果如下:
    undefined
    Uncaught ReferenceError: b is not defined

    这里的b没有使用var声明,所以没有变量提升

    示例六:

    console.log(a);
    console.log(window.b);
    
    var a = 10;
    b = 10;
    

    结果如下:
    undefined
    undefined

    这里b并没有使用 var声明,但是由于调用的是window.b,相当于调用一个对象的属性,属性不存在,返回undefined,因此不会报错。

    示例七:

    console.log(a, b); // 变量提升,默认值为 undefined
    
    var a = 10, b = 10;
    function fn() {
        console.log(a, b); // 由于下一行的 a 使用 var 声明,变量提升,默认值 undefined
                           // b 不是 var 声明的,不存在变量提升,
                           // 所以根据作用域链,向上查找,即为全局声明的 b
        var a = b = 11;
        console.log(a, b);
     }
    fn();
    console.log(a, b); // 在函数中改变了全局变量 b 的值
    

    结果如下:
    undefined undefined
    undefined 10
    11 11
    10 11

    示例八:

    function fn(a) {
       n = a;
       console.log(a);
       console.log(n);
       console.log('a' in window);
       console.log('n' in window);
    }
    fn(11);
    // console.log(a); // 报错 Uncaught ReferenceError: a is not defined
    console.log(n);
    

    结果如下:
    11
    11
    false
    true
    11

    在函数体内,不使用var声明的变量(参数是局部变量),会被视为全局变量,假如全局作用域中不存在此变量,则在函数执行时被创建。

    示例九:

    console.log(fn); // typeof fn ===> undefined
    fn();
    var fn = () => console.log(11); // typeof fn ===> function
    

    结果如下:
    undefined
    Uncaught TypeError: fn is not a function

    示例中是给使用var声明的变量赋值一个匿名函数,所以,fn作为变量,默认值是undefined,在赋值之前执行fn(),相当于执行一个变量,所以产生类型错误。

    通过之前,和之后的 typeof可以看出,赋值之前,把fn作为一个变量,之后把fn作为一个函数。

    示例十:

    console.log(a);
    if (false) {
      var a = 10;
    }
    console.log(a);
    

    结果如下:
    undefined
    undefined

    由于var没有块级作用域,所以声明的a是全局变量,变量提升默认值是undefined,由于if条件为false,所以不执行赋值操作,最后的值还是undefined。假如if条件为true,则会执行赋值操作。

    示例十一:

    console.log(f);
    // typeof f ===> undefined
    if (f()) {
       function f() {
           return true;
        }
    }
    

    结果如下:
    undefined
    Uncaught TypeError: f is not a function

    一般情况下,function声明的函数,可以在声明之前调用执行如:

    f();
    function f(){return true};
    

    然而,在if语句块中(低版本浏览器除外),使用function声明的函数和var声明变量一样,都只是先声明,然后变量提升,只有执行到的时候才会赋值,在if条件中的f现在还是undefined,因此,调用f()会出现语法错误。

    示例十二:

    console.log(f);
    
    if (true) {
        console.log(f);
    
        function f() {
            return true;
        }
    }
    

    结果如下:
    undefined
    ƒ f() {
      return true;
    }

    注意:if条件体内的第一句中f并不是一个变量,假如是var声明的变量,值是undefined,但它是function声明的函数,所以值是函数声明的字符串。

    示例十三:

        console.log(a);
        var a = 1
        function a() {
          console.log(1);
        }
        console.log(a);
    
        // a(); // 这里 a=1 调用变量报错
        function a() {
          console.log(2);
        }
        // a(); // 这里 a=2 调用变量报错
        var a = 2;
        function a() {
          console.log(3);
        }
        var a = () => { }; // 这里的 a 同样只是变量赋值
        var a;
        function a() {
          console.log(4);
        }
        console.log(a);
    

    结果如下:
    ƒ a() {
      console.log(4);
    }
    1
    () => { }

    在程序执行之前,先要考虑变量提升(除了在函数体内,先形参赋值,再变量提升),开始时使用var声明的变量提升,默认值是undefined,之后再使用var声明同名的变量,并不会有变量提升,只是相当于赋值操作;而function声明同名的函数,每次都会变量提升并覆盖初始值,即最后一次的function声明为默认值。之后,程序开始自上而下执行,越过函数体部分,只有函数再调用时才会进入函数体。

    假如没有对a重新赋值,不管在哪里调用都是对最后一次声明的函数的调用。在调用之前,如果对a重新赋值(不包括赋值一个匿名函数),a成为了一个变量,调用变量即会报错。

    相关文章

      网友评论

        本文标题:JavaScript 坑与技巧:变量提升机制

        本文链接:https://www.haomeiwen.com/subject/qayhiqtx.html