更好地理解javascript预编译

时间:2015-04-21 11:36:13

标签: javascript precompile

var foo=1;
function bar(){
  foo=10;
  return;
  function foo(){}
}
bar();
alert(foo);

我目前正在学习javascript如何在机器中实际运行,这是我在示例中看到的一段代码。我不知道为什么最终警报是1而不是10。所以我想知道任何人都可以帮我解释javascript虚拟机是如何实际执行这些代码的。谢谢!

3 个答案:

答案 0 :(得分:6)

这是由于function declaration hoisting

var foo=1;
function bar(){
  function foo(){} // This gets moved up here by the engine
  foo=10; // You've reassigned the local `foo` function to 10,
          // leaving the global `foo` untouched
  return;
}
bar();
alert(foo); // Since the foo has never changed in this scope, it's still 1

答案 1 :(得分:3)

  

我不知道为什么最后的警报是1而不是10。

因为foo中此行中的bar

foo = 10;

...是稍后在该函数中由函数声明声明的类似变量的东西:

function foo(){}

... foo以外的bar。那就是:

var foo=1;
function bar(){
  foo=10;             // <== This `foo`
  return;
  function foo(){}    // <== Is the `foo` declared here
}
bar();
alert(foo);

...不是在包含范围(foo)中声明的var foo

有两个原因正在发生:

  1. 在函数中的任何分步代码之前,函数声明在进入包含范围(在这种情况下为bar)时立即处理。这有时被称为“提升”声明(因为它们就像它们位于最顶端一样)。由于函数声明不是逐步代码,return对它是否被处理没有影响;它会在return发生之前得到处理。

  2. 函数声明还可以创建具有函数名称的变量。因此,函数声明中的foo实际上变为具有该名称的变量(更多信息如下) - 正如您在该代码中看到的那样,您可以为这些“变量”分配新值。

  3. 当您运行该代码时,这是JavaScript引擎所做的事情的顺序:

    1. 创建一个名为foo的变量,并为其指定初始值undefined

    2. 创建函数bar,在当前作用域中添加bar作为范围内符号(实际上是变量),并使其成为bar函数的引用。

    3. 启动该范围的分步代码。

    4. 将值1分配给foo

    5. 致电bar功能。

    6. 创建与foo调用相关的bar函数,在调用期间添加foo作为范围内符号(实际上是变量)并使其成为参考功能。

    7. 启动该范围的分步代码。

    8. 将值10分配给本地foo(用于引用该函数)。

    9. 退出函数。

    10. 使用该范围内的alert来调用foo,其范围仍为1

    11. 您可以阅读§10.4.3 of the spec及其链接部分中的所有血腥细节。


      *“类似变量的东西”在JavaScript中,每个执行上下文(全局上下文和通过调用函数创建的任何上下文等)都有一个对象,用于保存用于的各种名称。这种背景及其价值观;它被称为“绑定对象”。上下文的绑定对象(我在这里跳过一些不相关的细节)对于每个变量,函数声明和一些其他的东西都有属性,例如arguments伪数组,名称函数本身(参考函数)等。属性的名称是变量的名称,声明的函数等。这就是为什么在foo内分配bar会覆盖对foo中声明的bar函数的引用。而不是分配给外部范围中的变量。 foo 有效 bar中的局部变量,即使它未使用var声明,因为函数声明。

答案 2 :(得分:1)

这与名为 hoisting 的概念有关。 function foo基本上只是var foo = function ..的替代语法,因此在bar内,名称foo不会引用外部foo变量,而是引用本地定义的foo {1}}。此foo首先是一个函数,但后来被10覆盖。

现在,通过提升名称foo是&#34;保留&#34;在代码执行之前,在解析时确定范围。基本上,它执行如下:

function bar(){
  var foo = function () {};
  foo = 10;
  return;
}

因此它根本不会覆盖外部变量。