【问题标题】:JavaScript variable hoisting exampleJavaScript 变量提升示例
【发布时间】:2014-12-31 00:30:42
【问题描述】:

我对 JavaScript 中的变量提升有疑问。

考虑以下示例: ​

var myName = "Richard"; // Variable assignment (initialization)
​
​function myName () {
console.log ("Rich");
}
​
console.log(typeof myName); // string 

我真的很困惑为什么typeof myName 被返回为string

根据我的理解,该示例将按如下方式进行;

  1. 首先函数声明 (function myName ()) 将被提升到顶部,然后
  2. JS 解释器会读取var myName = "Richard" 行(因为函数声明优先于变量声明)。但是,由于已经有一个名为“myName”的属性,因此该语句将被忽略。

因此typeof myName 应该作为函数(而不是字符串)返回。

我的理解哪里不对?

【问题讨论】:

    标签: javascript hoisting


    【解决方案1】:

    JavaScript 有一个动态类型系统,即变量的类型可以随时间变化。基本上,您写的内容是正确的:首先,函数声明开始运行(在加载文件时),但随后存储在变量 myName 中的函数被字符串覆盖。

    唯一被忽略的是对var 的调用,因为实际上已经声明了变量。

    但是重新定义一个变量是完全有效的(这就是你在这里所做的,通过分配一个新值)。

    最后,您的样本不过是这样:

    var x = 23;
    x = 'foo';
    

    这也可以,x 将是 'foo',其类型将是 string。与您的示例唯一不同的是,在您的示例中,涉及function 类型的值。

    【讨论】:

      【解决方案2】:

      除了其他答案之外,还需要注意的是,如果您以下列方式声明您的函数:

      var myName = function() {
        console.log('Rich');
      }
      

      或者干脆

      myName = function(){
        console.log('Rich')
      }
      

      与“function myName ...”语法相反,typeof myName 将返回“function”

      【讨论】:

        【解决方案3】:

        2 年过去了,但也许它仍然与某人有关 你是对的,当解释一个对象时确实如此:

        • 扫描函数声明的上下文

          • 为找到的每个函数,在变量对象中创建一个属性
          • 如果函数名已经存在,则引用指针值将被覆盖
        • 扫描上下文中的变量声明

          • 对于找到的每个变量声明,在变量对象中创建一个属性,即变量名,并将值初始化为未定义
          • 如果变量对象中已经存在变量名,什么都不做,继续扫描

        但是,对于全局范围而言,情况似乎并非如此。 IE。当我定义一个对象时,输出与它应有的完全一样,当我在全局范围内定义相同时,它不是...... 仍然试图围绕这个来解决我的问题

        【讨论】:

          【解决方案4】:

          “提升”的想法是了解正在发生的事情的不好方法。换句话说,在我看来,“吊装”是对吊装的不好解释。

          真正发生的不是“吊装”。真正发生的是javascript分两个阶段执行代码:编译阶段和评估阶段。 javascript 社区将这种症状称为“提升”,但大多数人无法理解为什么要提升提升,因为他们认为 javascript 解释器具有这种称为“提升”的功能(他们没有)。

          实际发生的事情比吊装的想法更容易解释。规则是:

          1. Javascript 总是从上到下解析代码。它从不重新排序代码(它从不提升)。

          2. 有两个执行阶段:编译和评估。

          3. 所有声明都在编译阶段处理,编译阶段不会评估任何表达式(因为“评估”事情是在评估阶段完成的)。

          4. 所有表达式和任何其他需要评估的东西都在评估阶段进行处理。

          记住规则 1,所有解析都是自顶向下完成的,没有回溯,没有提升。

          让我们以您的示例为例,并通过记住 javascript 的编译和评估阶段来尝试理解它:

              var myName = "Richard"; // Variable assignment (initialization)
          ​    
           ​   function myName () {
                 console.log ("Rich");
              }
          
          ​    console.log(typeof myName); // string 
          
          1. 在编译阶段,解释器看到你声明了一个变量。它为该变量分配一块内存区域,并为其赋值undefined

          2. 在编译阶段,解释器看到你声明了一个函数。它还注意到函数名隐藏了变量名。因此它创建了一个函数“myName”(这意味着此时变量myName 指向该函数)。

          3. 编译阶段结束。现在我们进入评估阶段。

          4. 在评估阶段,解释器看到您将字符串分配给myName

          5. 当我们到达函数声明时,没有什么要评估的,因为声明是在编译阶段处理的。

          6. 在评估阶段,解释器看到你控制台记录myName 的类型。由于分配给它的最后一个东西是一个字符串,它打印“字符串”。

          请注意,如果您删除字符串赋值,那么myName 将是 typeof "function"。那是因为在这种情况下,最后分配给它的是声明的函数。

          有关两个执行阶段引起的其他细微差别,请参阅此相关问题:JavaScript function declaration and evaluation order

          【讨论】:

          • 我不认为你的解释是正确的。 “提升”是一种语言功能,虽然标准没有使用这个词,但该过程已准确记录——请参阅“声明绑定实例化”ecma-international.org/ecma-262/5.1/#sec-10.5
          【解决方案5】:

          因为Hoisting 你的变量和函数定义被移到了顶部,所以你有:

          var myName;
          // moved to top
          function myName () {
            console.log ("Rich");
          }
          
          // next your code
          myName = "Richard";
          
          console.log(typeof myName); // string 
          

          如果你像这样重写你的代码:

          var myName = "Richard"; // Variable assignment (initialization)
          ​
          myName = ​function () {  // Variable redefinition
            console.log ("Rich");
          }
          ​
          console.log(typeof myName); // function
          

          您的myName 变量现在是一个函数,因为只有myName 变量是hoisted

          var myName;
          
          myName = "Richard";     // Variable assignment (initialization)
          myName = ​function () {  // Variable redefinition
            console.log ("Rich");
          }
          ​
          console.log(typeof myName); // outputs 'function'
          

          【讨论】:

          • 您从示例中的函数声明更改为函数表达式,并且 - 不幸的是 - JavaScript 对它们的处理方式不同:在加载时扫描文件以查找函数声明时,函数表达式及其分配得到解决在运行时。因此,不幸的是,你的例子确实解释了一些东西,但没有解释什么。
          • @GoloRoden - 我已经解释了为什么myName 变量的类型是string 而不是function,接下来我做了一个例子,变量的类型是function ;-)
          猜你喜欢
          • 2016-01-14
          • 2015-06-22
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-01-01
          • 1970-01-01
          • 2019-05-07
          • 2021-12-23
          相关资源
          最近更新 更多