为何这种奇怪的行为?

时间:2014-02-19 15:10:28

标签: javascript

我正在以三种方式修改一段代码。在这3个条件中表现不同。请描述一下它是如何执行的?

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

为什么在第二种情况下它的打印未定义?在第三种情况下,我发送我的全局a作为参数,然后它也是未定义的打印。

2 个答案:

答案 0 :(得分: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();

此行为称为Variable Hoisting

修改 正如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);

答案 1 :(得分:2)

第二种情况是由于JavaScript执行上下文的工作方式而打印未定义。您可能遇到过吊装这个词。

为了更详细地解释它,当调用第二个函数时,解释器将进入一个包含两个阶段的过程。

创作阶段

  • 创建范围链
  • 创建参数,函数,变量,即所谓的变量对象
  • 确定“this”关键字的值

激活或代码执行阶段

  • 解释并执行代码

因此,当您调用myFunc()时,JavaScript解释器将创建一个执行上下文,您可以将其视为对象文字,如下所示:

myFuncExecutionContext = {
   scopeChain: { ... },
   variableObject: {
      arguments: {
        length: 0
      },
     a: undefined,
  },
  this: { ... }
}

您可以看到本地变量的初始值为undefined。在代码执行阶段,解释器将逐行运行函数;所以它看到的第一行是console.log(a);。解释器将查看variableObject以查看是否存在具有该名称的变量。如果不是,它将使用作用域链并尝试在外部作用域的变量对象中找到它。因为,变量对象中有a变量,它将读取它的值,这是未定义的。

然后它将执行第2行,它将为局部变量a赋值; var a=2;。然后它将执行最后一行 - console.log(a) - 它将打印我们之前分配的值。

同样的机制证明了为什么我们可以在定义函数之前调用它,只要我们使用函数声明语法。

someFunc(); // VALID
function someFunc(){  };

以下情况会导致错误:

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