【问题标题】:Javascript function scoping and hoistingJavascript函数作用域和提升
【发布时间】:2011-11-22 08:08:32
【问题描述】:

我刚刚阅读了一篇关于 JavaScript Scoping and Hoisting by Ben Cherry 的精彩文章,其中他给出了以下示例:

var a = 1;

function b() {
    a = 10;
    return;

    function a() {}
}
b();
alert(a);

使用上面的代码,浏览器会提示“1”。

我仍然不确定它为什么返回“1”。他说的一些事情浮现在脑海中,例如: 所有函数声明都被提升到顶部。您可以使用函数作用域变量。仍然没有为我点击。

【问题讨论】:

    标签: javascript scope scoping hoisting


    【解决方案1】:

    ES5:函数提升&变量提升

    function hoisting 的优先级是 greater 高于 variable hoisting

    "use strict";
    
    /**
     *
     * @author xgqfrms
     * @license MIT
     * @copyright xgqfrms
     * @created 2016-06-01
     * @modified
     *
     * @description function-hoisting.js
     * @augments
     * @example
     * @link
     *
     */
    
    (function() {
      const log = console.log;
    
      var a = 1;
      function b() {
        a = 10;
        log(`local a`, a)
        return;
        // function hoisting priority is greater than variable hoisting
        function a() {}
      }
      b();
      log(`global a`, a);
      // local a 10
      // global a 1
    })();
    
    
    
    

    等于

    (function() {
      const log = console.log;
    
      // define "a" in global scope
      var a = 1;
      function b() {
        // define "a" in local scope
        var a ;
        // assign function to a
        a = function () {};
        // overwrites local variable "a"
        a = 10;
        log(`local a`, a);
        return;
      }
    
      b();
      // log global variable "a"
      log(`global a`, a);
    
      // local a 10
      // global a 1
    })();
    
    

    吊装的原因

    var a = 1;                
    //"a" is global scope
    function b() {  
       var a = function () {}; 
       //"a" is local scope 
       var x = 12; 
       //"x" is local scope 
       a = 10;
       //global variable "a" was overwrited by the local variable "a"  
       console.log("local a =" + a);
       return console.log("local x = " + x);
    }       
    b();
    // local a =10
    // local x = 12
    console.log("global a = " + a);
    // global a = 1
    console.log("can't access local x = \n");
    // can't access local x = 
    console.log(x);
    // ReferenceError: x is not defined
    
    /**
     *  scpope & closure & hoisting (var/function)
     *  
     * 1. scpope : the global var can be access in any place(the whole file scope), local var only can be accessed by the local scope(function/block scope)!
     * Note: if a local variable not using var keywords in a function, it will become a global variable!
     * 
     * 2. closure : a function inner the other function, which can access local scope(parent function) & global scope, howerver it's vars can't be accessed by others! unless, your return it as return value!
     * 
     * 3. hoisting : move all declare/undeclare vars/function to the scope top, than assign the value or null!
     * Note: it just move the declare, not move the value!
     * 
     */
    
    

    ES6 let, const 不存在提升

    (() => {
      const log = console.log;
      log(a)
      // Error: Uncaught ReferenceError: Cannot access 'a' before initialization
      let a = 1;
    })();
    
    
    
    
    (() => {
      const log = console.log;
      log(b)
      // Error: Uncaught ReferenceError: Cannot access 'b' before initialization
      const b = 1;
    })();
    
    

    参考

    https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/var

    https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let

    https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/const

    【讨论】:

      【解决方案2】:

      用一句话来描述 javascript 中的托管是将变量和函数提升到声明它们的范围的顶部。

      我假设您是初学者,首先要正确理解提升,我们已经了解 undefinedReferenceError

      之间的区别
       var v;
       console.log(v);
       console.log(abc);
      /*
      The output of the above codes are:
      undefined
      ReferenceError: abc is not defined*/
      

      现在在下面的代码中我们看到了什么?变量和函数表达式被清除。

      <script>
      var totalAmo = 8;
      var getSum = function(a, b){
            return a+b;
      }
      </script>
      

      但真实的图片证明变量和函数都被提升到了作用域的顶部:

      console.log(totalAmo);
      console.log(getSum(8,9));
      var totalAmo = 8;
      var getSum = function(a, b){
            return a+b;
      }
      console.log(totalAmo);
      console.log(getSum(9,7));
      

      前两个日志的输出是 undefinedTypeError: getSum is not a function 因为 var totalAmogetSum 像下面这样被吊在其范围的顶部

       <script>
              var totalAmo;
              var getSum;
      
              console.log(totalAmo);
              console.log(getSum(8,9));
              var totalAmo = 8;
              var getSum = function(a, b){
                  return a+b;
              }
              console.log(totalAmo);
              console.log(getSum(9,7));
          </script>
      

      但对于函数声明,整个函数都被提升到其作用域的顶部。

      console.log(getId());
      function getId(){
         return 739373;
      }
      /* output: 739373, because the whole function hoisted on the top of the scope.*/
      

      现在同样的逻辑也适用于在函数范围内声明的变量、函数表达式和函数声明。 关键点:它们不会被吊到文件顶部;

      function functionScope(){
                  var totalAmo;
                  var getSum;
      
                  console.log(totalAmo);
                  console.log(getSum(8,9));
                  var totalAmo = 8;
                  var getSum = function(a, b){
                      return a+b;
                  }
              }
      

      因此,当您使用 var 关键字时,变量和函数会在作用域(全局作用域和函数作用域)的顶部提升。 letconst 呢,const 和 let 仍然像 var 一样知道全局作用域和函数作用域,但是 const 和 let 变量也知道另一个作用域称为阻塞范围。只要有代码块,就存在块作用域,例如 for 循环、if else 语句、while 循环等。

      当我们使用 const 和 let 在这些块范围内声明一个变量时,变量声明只会被提升到它所在的块的顶部,而不会被提升到父函数的顶部或它被提升的全局范围的顶部。

       function getTotal(){
                  let total=0;
                  for(var i = 0; i<10; i++){
                      let valueToAdd = i;
                      var multiplier = 2;
                      total += valueToAdd*multiplier;
                  }
                  return total;
              }
      

      上面例子中的变量会像下面这样被提升

       function getTotal(){
                  let total;
                  var multiplier;
                  total = 0;
                  for(var i = 0; i<10; i++){
                      let valueToAdd;
                      valueToAdd = i;
                      multiplier = 2;
                      total += valueToAdd*multiplier;
                  }
                  return total;
              }
      

      【讨论】:

        【解决方案3】:

        据我所知,变量声明和函数声明都会发生提升,例如:

        a = 7;
        var a;
        console.log(a) 
        

        JavaScript 引擎内部发生了什么:

        var a;
        a = 7;
        console.log(a);
        // 7
        

        或者:

        console.log(square(7)); // Output: 49
        function square(n) { return n * n; }
        

        它会变成:

        function square(n) { return n * n; }
        console.log(square(7)); // 49
        

        但是变量赋值、函数表达式赋值等赋值不会被提升: 例如:

        console.log(x);
        var x = 7; // undefined
        

        可能会变成这样:

        var x;
        console.log(x); // undefined
        x = 7;
        

        【讨论】:

          【解决方案4】:

          令人惊讶的是,这里的答案都没有提到作用域链中执行上下文的相关性。

          JavaScript 引擎将当前正在执行的代码包装在一个执行上下文中。基本执行上下文是全局执行上下文。每次调用新函数时,都会创建一个新的执行上下文并将其放入执行堆栈。想想其他编程语言中位于调用堆栈上的堆栈框架。后进先出。现在每个执行上下文在 JavaScript 中都有自己的变量环境和外部环境。

          我将使用下面的示例作为演示。

          1) 首先,我们进入全局执行上下文的创建阶段。词法环境的外部环境和变量环境都被创建了。全局对象被设置并放置在内存中,特殊变量“this”指向它。函数 a 及其代码以及具有未定义值的变量 myVar 被放置在全局变量环境的内存中。重要的是要注意函数 a 的代码没有被执行。它只是用函数 a 放在内存中。

          2) 其次,是执行上下文的执行阶段。 myVar 不再是未定义的值。它初始化为 1,存储在全局变量环境中。调用函数 a 并创建一个新的执行上下文。

          3) 在函数a的执行上下文中,它经历了自己的执行上下文的创建和执行阶段。它有自己的外部环境和变量环境,因此,有自己的词法环境。函数 b 和变量 myVar 存储在其变量环境中。此变量环境不同于全局变量环境。由于函数 a 在词法上(在代码中物理上)与全局执行上下文处于同一级别,因此它的外部环境是全局执行上下文。因此,如果函数 a 要引用一个不在其变量环境中的变量,它会搜索作用域链并尝试在全局执行上下文的变量环境中找到该变量。

          4) 函数 b 在函数 a 中被调用。创建了一个新的执行上下文。由于它在词汇上位于函数 a 中,因此它的外部环境是 a。所以当它引用 myVar 时,由于 myVar 不在函数 b 的变量环境中,它会在函数 a 的变量环境中查找。它在那里找到它并且 console.log 打印 2。但是如果变量不在函数 a 的变量环境中,那么由于函数 a 的外部环境是全局执行上下文,那么作用域链将继续在那里搜索。

          5) 函数 b 和 a 执行完毕后,从执行栈中弹出。单线程 JavaScript 引擎在全局执行上下文中继续执行。它调用 b 函数。但是全局变量环境中没有 b 函数,并且在全局执行上下文中没有其他外部环境可以搜索。因此 JavaScript 引擎会引发异常。

          function a(){
            function b(){
              console.log(myVar);
            }
          
            var myVar = 2;
            b();
          }
          
          var myVar = 1;
          a();
          b();
          > 2
          > Uncaught ReferenceError: b is not defined
          

          以下示例显示了作用域链。在函数b的执行上下文的变量环境中,没有myVar。所以它搜索它的外部环境,也就是函数 a。函数 a 在其变量环境中也没有 myVar。所以 Engine 搜索函数 a 的 Outer Environment,也就是全局 Execution Context 的 Outer Environment,myVar 就是在里面定义的。因此,console.log 打印 1。

          function a(){
            function b(){
              console.log(myVar);
            }
          
            b();
          }
          
          var myVar = 1;
          a();
          > 1
          

          关于执行上下文和与之相关的词法环境,包括外部环境和变量环境,在 JavaScript 中启用变量的作用域。即使您多次调用同一个函数,对于每次调用,它都会创建自己的执行上下文。因此,每个执行上下文都会在其变量环境中拥有自己的变量副本。没有共享变量。

          【讨论】:

            【解决方案5】:

            提升是 JavaScript 的行为概念。提升(比如移动)是解释变量应该如何以及在何处声明的概念。

            在 JavaScript 中,变量可以在使用后声明,因为函数声明和变量声明总是被 JavaScript 解释器不可见地移动(“提升”)到其包含范围的顶部。

            我们在大多数情况下会遇到两种类型的吊装。

            1.变量声明提升

            让我们通过这段代码来理解这一点。

             a = 5; // Assign 5 to a
             elem = document.getElementById("demo"); // Find an element 
             elem.innerHTML = a;                     // Display a in the element
             var a; // Declare a
              //output-> 5
            

            这里变量 a 的声明将在编译时由 javascript 解释器以不可见的方式托管到顶部。所以我们能够得到a的值。但是这种声明变量的方式不推荐,因为我们应该像这样声明变量到top。

             var a = 5; // Assign and declare 5 to a
             elem = document.getElementById("demo"); // Find an element 
             elem.innerHTML = a;                     // Display a in the element
              // output -> 5
            

            考虑另一个例子。

              function foo() {
                 console.log(x)
                 var x = 1;
             }
            

            实际上是这样解释的:

              function foo() {
                 var x;
                 console.log(x)
                 x = 1;
              }
            

            在这种情况下,x 将是未定义的

            包含变量声明的代码是否已执行无关紧要。考虑这个例子。

              function foo() {
                 if (false) {
                     var a = 1;
                 }
                 return;
                 var b = 1;
              }
            

            这个函数原来是这样的。

              function foo() {
                  var a, b;
                  if (false) {
                    a = 1;
                 }
                 return;
                 b = 1;
              }
            

            在变量声明中,只有变量定义提升,而不是赋值。

            1. 函数声明提升

            与提升函数体或赋值的变量不同,它也会被提升。考虑这段代码

             function demo() {
                 foo(); // this will give error because it is variable hoisting
                 bar(); // "this will run!" as it is function hoisting
                 var foo = function () {
                     alert("this would not run!!");
                 }
                 function bar() { 
                     alert("this will run!!");
                 }
             }
             demo();
            

            现在我们了解了变量和函数提升,现在让我们了解这段代码。

            var a = 1;
            function b() {
              a = 10;
              return;
               function a() {}
            }
            b();
            alert(a);
            

            这段代码会变成这样。

            var a = 1;                 //defines "a" in global scope
             function b() {  
               var a = function () {}; //defines "a" in local scope 
                a = 10;                 //overwrites local variable "a"
                return;      
             }       
             b();       
             alert(a); 
            

            函数 a() 将在 b() 内具有局部作用域。 a() 将在解释带有其定义的代码时移到顶部(仅在函数提升的情况下),因此 a now 将具有本地范围,因此不会影响 a 的全局范围,而在函数 b() 中有自己的范围.

            【讨论】:

              【解决方案6】:

              长篇大论!

              但它会净化空气!

              Java Script 的工作方式是它涉及两个步骤:

              1. 编译(可以这么说)- 这一步注册变量和函数声明及其各自的范围。它不涉及评估函数表达式:var a = function(){} 或变量表达式(例如在 var x =3; 的情况下将 3 分配给 x,这只不过是 R.H.S 部分的评估。)

              2. 解释器:这是执行/评估部分。

              检查以下代码的输出以了解:

              //b() can be called here!
              //c() cannot be called.
              console.log("a is " + a);
              console.log("b is " + b);
              console.log("c is " + c);
              var a = 1;
              console.log("Now, a is " + a);
              var c = function() {};
              console.log("Now c is " + c);
              
              function b() {
                //cannot write the below line:
                //console.log(e); 
                //since e is not declared.
                e = 10; //Java script interpreter after traversing from this function scope chain to global scope, is unable to find this variable and eventually initialises it with value 10 in global scope.
                console.log("e is " + e) //  works!
                console.log("f is " + f);
                var f = 7;
                console.log("Now f is " + f);
                console.log("d is " + d);
                return;
              
                function d() {}
              }
              b();
              console.log(a);

              让我们打破它:

              1. 在编译阶段, “a”将在全局范围内注册,值为“undefined”。 'c' 也是如此,此时它的值将是 'undefined' 而不是 'function()'。 'b' 将被注册为全局范围内的函数。 在b 的范围内,'f' 将被注册为此时未定义的变量,而函数'd' 将被注册。

              2. 解释器运行时,可以在解释器到达实际表达式行之前访问声明的变量和function()(而不是表达式)。因此,变量将打印为“undefined”,并且可以更早地调用声明的匿名函数。但是,在表达式初始化之前尝试访问未声明的变量会导致如下错误:

              console.log(e)
              e = 3;

              现在,当你有同名的变量和函数声明时会发生什么。

              答案是 - 函数总是在之前被提升,如果声明了同名变量,它被视为重复并被忽略。请记住,顺序并不重要。函数总是优先的。但是在评估阶段,您可以将变量引用更改为任何内容(它存储最后一次分配的内容)看看下面的代码:

              var a = 1;
              console.log("a is " + a);
              
              function b() {
                console.log("a inside the function b is " + a); //interpreter finds                                'a' as function() in current scope. No need to go outside the scope to find 'a'.
                a = 3; //a changed
                console.log("Now a is " + a);
                return;
              
                function a() {}
              }
              var a; //treated as duplicate and ignored.
              b();
              console.log("a is still " + a + " in global scope"); //This is global scope a.

              【讨论】:

                【解决方案7】:

                吊装是为我们设计的一个概念,目的是让我们更容易理解。实际发生的是声明首先针对其范围完成,然后分配将发生(不是同时)。

                当声明发生时,var a,然后是 function b,在 b 范围内,声明了 function a

                此函数 a 将隐藏来自全局范围的变量 a。

                声明完成后,值分配将开始,全局a 将获得值1,而内部function b 将获得10。 当您执行alert(a) 时,它将调用实际的全局范围变量。 对代码的这个小改动会让它更清晰

                        var a = 1;
                
                    function b() {
                        a = 10;
                        return a;
                
                        function a() { }
                    }
                
                    alert(b());
                    alert(a);
                

                【讨论】:

                • 奇怪的是,即使在 codeschool.com 的课程中​​,这么多专家也提到了提升,这只不过是对所发生事情的简单看法,实际上提升根本不会发生。参考:1) developer.mozilla.org/en-US/docs/Glossary/Hoisting 2) JavaScript Ninja 2/e 的第 5 章,作者:john resig、bear bebeault、josip maras
                【解决方案8】:

                这一切都取决于变量“a”的范围。让我通过将范围创建为图像来进行解释。

                这里 JavaScript 将创建 3 个作用域。

                i) 全局范围。 ii) 函数 b() 范围。 iii) 函数 a() 作用域。

                当你调用 'alert' 方法时,它的明确范围是属于全局的,所以它只会从全局范围中选择变量 'a' 的值,即 1。

                【讨论】:

                  【解决方案9】:

                  提升 在 JavaScript 中意味着,变量声明在执行任何代码之前在整个程序中执行。因此在代码的任何地方声明一个变量,就相当于在开头声明它。

                  【讨论】:

                    【解决方案10】:

                    这个小sn-p代码的争论焦点是什么?

                    案例 1:

                    function b 的主体中包含function a(){} 定义,如下所示。 logs value of a = 1

                    var a = 1;
                    function b() {
                      a = 10;
                      return;
                    
                      function a() {}
                    }
                    b();
                    console.log(a); // logs a = 1
                    

                    案例 2

                    function b 的主体内排除function a(){} 定义,如下所示。 logs value of a = 10

                    var a = 1;
                    function b() {
                      a = 10;  // overwrites the value of global 'var a'
                      return;
                    }
                    b();
                    console.log(a); // logs a = 10
                    

                    观察将帮助您了解语句console.log(a) 记录以下值。

                    案例 1: a = 1

                    案例 2: a = 10

                    职位

                    1. var a 已在全局范围内以词法方式定义和声明。
                    2. a=10 该语句将值重新分配给 10,它在词法上位于函数 b 内。

                    两种情况的解释

                    因为function definition with name property a 与variable a 相同。 function body b 中的 variable a 成为局部变量。上一行暗示a的全局值保持不变,a的局部值更新为10。

                    所以,我们想说的是下面的代码

                    var a = 1;
                    function b() {
                      a = 10;
                      return;
                    
                      function a() {}
                    }
                    b();
                    console.log(a); // logs a = 1
                    

                    由JS解释器解释如下。

                    var a = 1;
                    function b() {
                      function a() {}
                      a = 10;
                      return;
                    
                    
                    }
                    b();
                    console.log(a); // logs a = 1
                    

                    但是,当我们删除 function a(){} definition,在函数 b 之外声明和定义的 value of 'a' 时,该值将被覆盖,并在情况 2 中更改为 10。该值被覆盖,因为 a=10 指的是全局声明,如果要在本地声明,我们必须写var a = 10;

                    var a = 1;
                    function b() {
                      var a = 10; // here var a is declared and defined locally because it uses a var keyword. 
                      return;
                    }
                    b();
                    console.log(a); // logs a = 1
                    

                    我们可以通过将function a(){} definition 中的name property 更改为'a' 以外的其他名称来进一步澄清我们的疑问

                    var a = 1;
                    function b() {
                      a = 10; // here var a is declared and defined locally because it uses a var keyword. 
                      return;
                    
                      function foo() {}
                    }
                    b();
                    console.log(a); // logs a = 1
                    

                    【讨论】:

                      【解决方案11】:

                      scpope & 闭包 & 提升 (var/function)

                      1. scpope : 全局变量可以在任何地方访问(整个文件 范围),本地变量只能由本地访问 范围(函数/块范围)!
                        注意:如果一个局部变量没有使用 函数中的var关键字,它将成为一个全局变量!
                      2. closure : 另一个函数内部的函数,可以访问 本地范围(父函数)和全局范围,但是它是 vars 其他人无法访问!除非,您将其作为返回值返回!
                      3. 提升:将所有声明/取消声明变量/函数移动到范围 顶部,而不是赋值或为空!
                        注意:它只是移动声明,而不是移动值!

                      var a = 1;                
                      //"a" is global scope
                      function b() {  
                         var a = function () {}; 
                         //"a" is local scope 
                         var x = 12; 
                         //"x" is local scope 
                         a = 10;
                         //global variable "a" was overwrited by the local variable "a"  
                         console.log("local a =" + a);
                         return console.log("local x = " + x);
                      }       
                      b();
                      // local a =10
                      // local x = 12
                      console.log("global a = " + a);
                      // global a = 1
                      console.log("can't access local x = \n");
                      // can't access local x = 
                      console.log(x);
                      // ReferenceError: x is not defined
                      【解决方案12】:

                      这是我对答案的回顾,其中包含更多注释和一个伴奏的小提琴。

                      // hoisting_example.js
                      
                      // top of scope ie. global var a = 1
                      var a = 1;
                      
                      // new scope due to js' functional (not block) level scope
                      function b() {
                          a = 10; // if the function 'a' didn't exist in this scope, global a = 10
                        return; // the return illustrates that function 'a' is hoisted to top
                        function a(){}; // 'a' will be hoisted to top as var a = function(){};
                      }
                      
                      // exec 'b' and you would expect to see a = 10 in subsequent alert
                      // but the interpreter acutally 'hoisted' the function 'a' within 'b' 
                      // and in doing so, created a new named variable 'a' 
                      // which is a function within b's scope
                      b();
                      
                      // a will alert 1, see comment above
                      alert(a);
                      

                      https://jsfiddle.net/adjavaherian/fffpxjx7/

                      【讨论】:

                        【解决方案13】:

                        这是因为变量名称与函数名称相同,意思是“a”。 因此,由于 Javascript 提升,它尝试解决命名冲突,它将返回 a = 1。

                        我也对此感到困惑,直到我阅读了关于“JavaScript 提升”http://www.ufthelp.com/2014/11/JavaScript-Hoisting.html987654321@ 的这篇文章

                        希望对你有帮助。

                        【讨论】:

                          【解决方案14】:
                          1. 函数声明function a(){}首先被提升,它的行为类似于var a = function () {};,因此在本地范围内创建a
                          2. 如果您有两个同名变量(一个在全局另一个在本地),则局部变量总是优先于全局变量。
                          3. 当您设置a=10 时,您设置的是局部变量a,而不是全局变量。

                          因此,全局变量的值保持不变,你会得到,alerted 1

                          【讨论】:

                            【解决方案15】:

                            函数提升意味着函数被移动到其作用域的顶部。也就是说,

                            function b() {  
                               a = 10;  
                               return;  
                               function a() {} 
                            } 
                            

                            将被解释者重写为这个

                            function b() {
                              function a() {}
                              a = 10;
                              return;
                            }
                            

                            很奇怪,嗯?

                            另外,在这种情况下,

                            function a() {}
                            

                            表现与

                            相同
                            var a = function () {};
                            

                            所以,本质上,这就是代码正在做的事情:

                            var a = 1;                 //defines "a" in global scope
                            function b() {  
                               var a = function () {}; //defines "a" in local scope 
                               a = 10;                 //overwrites local variable "a"
                               return;      
                            }       
                            b();       
                            alert(a);                 //alerts global variable "a"
                            

                            【讨论】:

                            • 那么所有的函数声明最终都赋值给了一个变量?
                            • @dev.e.loper 是的,在 Javascript 中,函数是一流的对象,就像字符串和数字一样。这意味着它们被定义为变量,可以传递给其他函数,存储在数组中,等等。
                            • 函数体绝不是“重写”的。各种 ECMAScript 标准明确规定在代码执行开始之前处理变量和函数声明。也就是说,什么都没有移动,它与执行顺序有关(因此我不喜欢“提升”一词,它暗示移动或重新排列)。在您重新编写的代码中,声明 var a 应该在函数声明之前,而赋值 a = 1 应该在之后。但请注意,这并没有被解析器、标记器、解释器、编译器等指定为实际发生,它只是一个等价物。
                            • @RobG 当然,我想您可以将描述称为小"lie to children",但最终行为是相同的,无论是从字面上重新排列代码还是重新排列执行顺序。幕后实际发生的更多是学术问题,甚至可能取决于实现。
                            • “此外,在这种情况下,function a() {} 的行为与 var a = function () {}; 相同” — 这在两个方面是不正确的:首先,如果有的话,它会一直是var a = function a() {};(该函数实际上不是匿名的),其次,这两种形式不可互换,因为从var a = function a() {}; 开始,只有var a; 部分会被提升。 a = function a() {}; 部分仍然在 return 语句后面。因为原始形式是函数声明而不是函数表达式,所以它实际上是作为一个整体被提升的。
                            【解决方案16】:

                            函数a在函数b内部被提升:

                            var a = 1; 
                            function b() { 
                               function a() {} 
                               a = 10; 
                               return;
                            } 
                            b(); 
                            alert(a);
                            

                            这几乎就像使用var:

                            var a = 1; 
                            function b() { 
                               var a = function () {};
                               a = 10; 
                               return;
                            } 
                            b(); 
                            alert(a);
                            

                            函数在本地声明,设置a只发生在本地范围内,而不是全局变量。

                            【讨论】:

                            • 这一行“var a = function () {};”让一切都清楚了。基本上JavaScript是动态语言,而“function”也是JavaScript中的一个对象。
                            【解决方案17】:

                            function a() { } 是一个函数语句,它创建一个a 局部于b 函数的变量。
                            解析函数时会创建变量,无论是否执行var 或函数语句。

                            a = 10 设置这个局部变量。

                            【讨论】:

                            • 实际上a = 10 在执行函数b 时在global 范围内设置了一个变量,除非您添加"use strict"(在支持该指令的环境中)。
                            • @Sean:不,因为函数语句创建了一个本地标识符。
                            • ......和......你是对的。没有意识到函数提升的特殊后果。谢谢!
                            【解决方案18】:

                            您必须记住的是,它会解析整个函数并在执行之前解析所有变量声明。所以....

                            function a() {} 
                            

                            真的变成了

                            var a = function () {}
                            

                            var a 强制它进入局部作用域,变量作用域贯穿整个函数,所以全局变量 a 仍然是 1,因为你已经通过将 a 声明为局部作用域,使其成为函数。

                            【讨论】:

                              猜你喜欢
                              • 2017-01-16
                              • 2013-10-20
                              • 1970-01-01
                              • 1970-01-01
                              • 1970-01-01
                              • 1970-01-01
                              • 1970-01-01
                              • 2023-03-28
                              • 1970-01-01
                              相关资源
                              最近更新 更多