【问题标题】:LET vs VAR and Hoisting from Block Scope to Global ScopeLET vs VAR 以及从块作用域提升到全局作用域
【发布时间】:2020-07-01 21:51:26
【问题描述】:

根据问题:

Understanding let vs. var hoisting

Are variables declared with let or const not hoisted in ES6?

我不明白当提升将变量从块范围提升到全局范围时会发生什么。

在我的代码中,我有:

<script>

    "use strict";

    let PageInit = null;

    document.addEventListener("DOMContentLoaded", () => {

        PageInit = new IPageInit();

        doSomething();

    });

    function doSomething() {
        alert(PageInit.RefreshCounter); // 60 //correct
    }

</script>

在全局范围内创建的PageInitdoSomething() 可见。

但是,如果我这样做:

<script>

    "use strict";

    document.addEventListener("DOMContentLoaded", () => {

        var PageInit = new IPageInit();

        doSomething();

    });

    function doSomething() {
        alert(PageInit.RefreshCounter); // referenceError
    }

</script>

我没有正确理解提升。我预计块范围内的var PageInit 会被提升到全局范围内,首先是&lt;script&gt; 标记内。

但事实并非如此。

谁能解释为什么不呢?或者它会被吊到哪里?

【问题讨论】:

    标签: javascript hoist


    【解决方案1】:
    document.addEventListener("DOMContentLoaded", () => {
    
        var PageInit = new IPageInit();
    
        doSomething();
    
    });
    

    var 具有功能范围。这意味着无论您在函数中的何处声明变量,它都可用于整个函数。

    function fn () {
      console.log(b)
      var b = 10
    }
    
    fn()
    
    /* this is same as writing
    function fn () {
      var b ======================> hoisted
      console.log(b)
       b = 10
    }
    */

    这并不意味着在函数内部声明的变量在函数外部可用。 这就是为什么PageInitdoSomething 函数中给出参考错误的原因。您必须在函数外部初始化变量才能不会出现此错误

    【讨论】:

      【解决方案2】:

      JavaScript 中的作用域

      JavaScript 中的作用域定义了变量、对象和函数的可访问性。

      JavaScript 中有两种作用域。

      1. 全球范围
      2. 本地范围

      全球范围

      在任何函数之外声明的变量都成为全局变量。可以从任何函数访问和修改全局变量。

      本地范围

      在任何函数中使用 var 关键字声明的变量称为局部变量。不能在函数声明之外访问或修改局部变量。

      我们都知道let 是块作用域,var 是它的当前执行上下文。

      结论

      在您的第一个示例中,let 可以访问,因为它的范围是全局的,并且他在主块中。 在您的第二个示例中,var 在它的本地范围内,这就是它无法输出它的值的原因

      【讨论】:

        【解决方案3】:

        我无法弄清楚您在脚本中的意图。但是,无论如何....

        不,var 在其“通用范围”内有效,因此“在其函数和子函数的树中”。因此,您找不到它,因为您正在实例化一种新情况,如果未在参数之间传递,该 var 将丢失。

        如果你使用 let 那就更糟了,因为它只在那个函数内有效并且如果不作为参数传递就不会访问子函数。

        在所有这一切中,您是在一个事件系统上进行操作...事件类似于 ajax(仅在瞬间创建并丢失该事件)。很难通过提取数据来处理它们而不将它们保存在某处或将其从函数传递到另一个函数。

        有助于理解: https://dev.to/sarah_chima/var-let-and-const--whats-the-difference-69e

        更正确的版本应该是:

        简单的想法(我没有测试过,但逻辑是这样的)

        var XXX;
        
        document.addEventListener("DOMContentLoaded", XXX => {
        
            XXX = new IPageInit();
        
            doSomething(XXX);
        
        }, false); 
        
        function doSomething(myval) {
            alert(myval); // now have XXX here 
        }
        

        所以... xxx 传递到事件成功 => 并传递给 doSomethig。

        或者...

        document.addEventListener("DOMContentLoaded", () => {
        
            var XXX = getaval();
        
            doSomething(XXX);
        
        }, false); 
        
        function getaval() {
             return IPageInit(); // now have XXX here 
        }
        
        function doSomething(myval) {
            alert(myval); // now have XXX here 
        }
        

        所以... 在事件 => 得到或做你所拥有的。如果什么都没有……得到。

        我希望我至少对你有所帮助。

        【讨论】:

          【解决方案4】:

          我不明白当提升将变量从块范围提升到全局范围时会发生什么。

          这永远不会发生。

          托管影响何时变量出现,而不是在哪里

          document.addEventListener("DOMContentLoaded", () => {
          
              PageInit = new IPageInit();
          

          这隐含地声明了一个全局。它不是托管的。在函数运行之前,该变量不存在。在此之前尝试读取变量将导致异常。

          document.addEventListener("DOMContentLoaded", () => {
          
              var PageInit = new IPageInit();
          

          var 在它声明的函数范围内声明一个变量。所以它不会创建一个全局变量。

          提升了……但由于它是函数中的第一行,因此没有实际区别。

          【讨论】:

          • 呃。完全尴尬。我完全忽略了 EventListener 的主体是一个函数这一事实。这甚至是我自己对胖箭头函数的批评之一是实际上没有关键字“function”,您更有可能忽略它们作为函数,[而不是使用匿名函数,ala,“function () {}” ]。这正是我在这里所做的。尽管如此,这是最接近我希望学习的答案。谢谢。
          猜你喜欢
          • 2016-04-05
          • 2015-06-25
          • 1970-01-01
          • 2013-10-20
          • 2015-08-22
          • 2017-01-16
          • 1970-01-01
          • 2014-03-20
          • 1970-01-01
          相关资源
          最近更新 更多