为什么会出现这种奇怪的行为?

10

我正在以三种方式修改代码。在这三个条件下它的行为有所不同。请描述它是如何执行的?

var a=1;
function myFunc(){
    console.log(a);
    console.log(a)
}
myFunc();
//Output is:
1 
1

var a=1;
function myFunc(){
    console.log(a);
    var a=2;
    console.log(a)
}
myFunc();
//Output is:
undefined
2

var a=1;
function myFunc(){
    console.log(a);
    var a=2;
    console.log(a)
}
myFunc(a);
//Output is:
undefined
2
在第二种情况下为什么会打印undefined?而在第三种情况下,即使我将全局变量a作为参数发送,它也会打印undefined。

1
简而言之:提升。这是一个不错的链接:http://www.adequatelygood.com/JavaScript-Scoping-and-Hoisting.html - Matt Burland
这被称为变量提升 - code-jaff
1
http://www.adequatelygood.com/JavaScript-Scoping-and-Hoisting.html - ashley
2
没有其他人提到,但在最后一种情况下,将“a”作为参数传递并不会改变任何内容,因为您的函数不会对传递给它的参数执行任何操作。如果您将函数声明更改为“function myFunc(a)”,那么它将按预期工作(输出1,2)。 - Matt Burland
你应该修改你的问题标题,例如:“为什么我的全局变量未定义?” - jambriz
2个回答

16

这是因为 JavaScript 将 var 声明提升到作用域的顶部,所以你的代码实际上是这样的:

var a = 1;
function myFunc(){
    var a;            // a is redeclared, but no value is assigned
    console.log(a);   // therefore it evaluates to undefined
    a = 2;            // now a = 2
    console.log(a);   // and then it logs to 2
}
myFunc();

这种行为被称为变量提升

编辑 正如Beterraba所说,在第三个代码中,它记录undefined,因为函数头中未声明参数:

var a = 1;
function myFunc(a) {    // a is declared
    console.log(a);     // now a logs 1
    var a = 2;          // now a = 2
    console.log(a);
}
myFunc(a);

技术术语是“提升”,顺便说一下。 - Langdon
谢谢,我在试着回忆。 - Danilo Valente
第三种情况不起作用,因为该函数没有接收任何参数。 - Beterraba
@MichaelBerkowski 已经在答案中提到了。但还是谢谢您 :) - Danilo Valente
@DaniloValente 哦,确实,抱歉。 - Michael Berkowski
谢谢你的回答。我现在知道了提升的事情 :) - Paul Shan

2
第二种情况是由于JavaScript执行上下文的工作方式而导致打印未定义。你可能听说过"提升"这个术语。
更详细地解释一下,当调用第二个函数时,解释器将进入一个包含两个阶段的过程。
创建阶段 - 创建作用域链 - 创建参数、函数、变量,即所谓的变量对象 - 确定"this"关键字的值
激活或代码执行阶段 - 解释和执行代码
因此,当你调用myFunc()时,JavaScript解释器将创建一个执行上下文,你可以将其视为一个对象文字,看起来像这样:
myFuncExecutionContext = {
   scopeChain: { ... },
   variableObject: {
      arguments: {
        length: 0
      },
     a: undefined,
  },
  this: { ... }
}

你可以看到本地变量 a 的初始值为 undefined。在代码执行阶段,解释器将逐行运行函数;所以它看到的第一行是 console.log(a);。解释器将查看 variableObject 是否有该名称的变量。如果没有,它将使用作用域链并尝试在外部作用域的变量对象中定位它。由于变量对象中有变量 a,它将读取其值,即 undefined。
然后它将转到第二行,其中将为本地变量 a 赋值;var a=2;。然后它将执行最后一行 - console.log(a) - 这将打印我们之前分配的值。
同样的机制解释了为什么我们可以在定义函数之前调用它,只要我们使用函数声明语法。
someFunc(); // VALID
function someFunc(){  };

以下代码会导致错误:

someFunc(); // TypeError: undefined is not a function
var someFunc = function() {  }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接