LET 与 VAR 以及从块作用域提升到全局作用域

LET vs VAR and Hoisting from Block Scope to Global Scope

鉴于问题:

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

在我的代码中,我有:

<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 会被提升到全局范围内,首先是 <script> 标记内。

但事实并非如此。

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

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
}
*/

这并不意味着函数内声明的变量在函数外可用。 这就是 PageInit in doSomething 函数给出引用错误的原因。您必须在函数外部初始化变量才能避免出现此错误

I do not understand what happens when hoisting lifts a variable out of block scope, into global scope.

这永远不会发生。

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

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

    PageInit = new IPageInit();

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

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

    var PageInit = new IPageInit();

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

提升了……但是因为它是函数的第一行,所以没有实际区别。

范围在JavaScript

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

JavaScript中有两种作用域。

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

全局范围

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

局部作用域

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

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

结论

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

我无法理解您在脚本中的意图。然而无论如何....

不,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 
}

所以...在活动中 => 得到或做你拥有的。如果没有...得到。

我希望我至少对你有用了一点。