【问题标题】:If a var in JavaScript is defined twice, which definition should the interpreter take? [duplicate]如果 JavaScript 中的 var 定义了两次,解释器应该采用哪个定义? [复制]
【发布时间】:2019-10-15 08:46:48
【问题描述】:

我是 JavaScript 新手,正在尝试理解提升和作用域的概念。

案例 1

var name;

function logName(num) {
  console.log(name, num);
}

logName(1);
name = "Auro";
logName(2);

我在控制台中有以下输出

Auro 1
Auro 2

如果我对hoisting 的理解正确,JS 引擎会首先提升一个变量的声明,然后自动为其分配一个值undefined。只有遇到赋值(=)操作符时,才会真正给它赋值。

如果我上面的理解是正确的,那么第一次调用logName函数时,变量name应该打印了undefined,但它打印的是值。

案例 2

var name;

function logName(num) {
  console.log(name, num);
}

logName(1);
name = "Auro";
logName(2);
name = "Baner";

控制台输出:

Baner 1
Auro 2

这让我更加困惑。这里第一次调用函数logName 选择了后来对变量的赋值并打印了Baner,然而,第二次调用选择了前一个赋值,即Auro

这里发生了什么?我错过了什么?

【问题讨论】:

  • 第一个日志不输出Auro 1
  • 在这些例子中都没有我得到你声称得到的东西。
  • 您是否在控制台中多次测试这些?如果你是,我猜name 从你上次运行它时仍然存在
  • 这里的问题是一个错误的变量名! developer.mozilla.org/en-US/docs/Web/API/Window/name
  • @CodeManiac 是的。第一个日志不输出,只有重新运行才能输出。谢谢指出

标签: javascript function scope var hoisting


【解决方案1】:

除了其他答案,我可以说,只是不使用 var 而是使用 ES6 letconst 代替,“令人惊讶的行为”将消失。

let name;

function logName(num) {
  console.log(name, num);
}

logName(1);
name = "Auro";
logName(2);
name = "Baner";

【讨论】:

    【解决方案2】:

    在全局范围内,name 指的是window.name,即窗口的name 属性-在您给出的示例中是sif1sif2(可能是“Snippet IFrame 1/2 ")。

    由于window.name 已经存在,全局范围内的var name; 什么都不做。变量已定义。

    直到您覆盖它 - 请注意,您再次设置了全局 window.name 属性。而且,根据浏览器设置,这可能会在页面重新加载时持续存在(因为您要命名整个 window)。这解释了为什么您会看到值“坚持”。

    【讨论】:

    • 很好地调用了 iframe 名称。当我更新问题以使它们成为 sn-ps 时,这让我陷入了循环,^_^
    • 如果您按蓝色的“运行...”按钮两次,那么浏览器也会在您的计算机中打开新标签页 - 还是仅在我的本地浏览器中才能这样工作?
    • @KamilKiełczewski 那是因为重命名window.name后,“运行”按钮无法再找到具有所需名称的框架,因此打开了一个具有该名称的新窗口/选项卡。
    【解决方案3】:

    没有任何指定的输出匹配,因为最初您的值 name 等于 window.name,所以最初 name 变量的值将等于 winow.name 并且一旦覆盖它,您就会得到新的价值

    让我们了解这一切是如何运作的

    你可以这样理解代码执行有两个阶段

    1. 创建阶段
    2. 执行阶段

    创建阶段:- 在创建阶段,函数按原样提升在顶部,而变量被提升但没有分配值(或者您可以说它的价值是未定义的)

    执行阶段:-在执行上下文中,当变量到达发生赋值的行时,它会为变量赋值

    var name;
    
    function logName(num) {
      console.log(name, num);
    }
    
    logName(1);
    name = "Auro";
    logName(2);
    name = "Baner";

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-08-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-02-01
      相关资源
      最近更新 更多