JavaScript基础混乱

时间:2016-12-07 10:42:19

标签: javascript

您好我正在尝试理解JavaScript基础知识,并且陷入了一个条件。

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

这里alert(foo)会给我1,我知道在return语句之后,函数foo()将不会执行。但现在如果改变代码:

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

在条形函数中,如果我将删除函数foo()。然后alert(foo)会给我10

请帮助,如果有人能解释我为什么?

6 个答案:

答案 0 :(得分:7)

这称为 Javascript悬挂

我将尝试详细解释它。这就是我们所拥有的

var foo = 1;

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

bar();
alert(foo);

解释器会将其重写为

var foo = 1;

function bar(){
  function foo(){}  // this is also equal to var foo = function(){};
  foo = 10;       
  return;      
}

bar();
alert(foo);

现在向您解释提升的代码。

var foo = 1; // global variable; 

function bar(){
  var foo = function(){};  // foo is local variable of type function
  foo = 10;                // foo is changed to hold a number
  return;      
}

bar();
alert(foo);  // you alert global variable.

正如您所看到的,代码function foo(){}是否存在,它被视为bar()范围内的局部变量,foo的任何更改都被视为局部变量更改。 。

  • 当您在function foo(){} bar()时,您甚至没有触及全局变量..因此提醒1

  • 当您没有 function foo(){}时,您正在触及全局变量,因此会发出警告10

    现在我希望你理解输出..

答案 1 :(得分:4)

  

我知道在return语句之后,函数foo()将不会执行。

那不是真的。

函数声明已悬挂。

function foo(){}创建一个名为foo的局部变量(为其分配新函数),然后foo = 10覆盖它。您永远不会测试foo变量的值。

  

在bar函数中,如果我将删除函数foo()。然后警报(foo)会给我10个

您不再拥有名为foo的局部变量,因此您将覆盖具有相同名称的全局变量。

比较



(function() {
  console.log("Version 1");
  var foo = 1;

  function bar() {
    console.log("At top of bar, foo is " + foo);
    foo = 10;
    console.log("After assignment in bar, foo is " + foo);
    return;

    function foo() {}
  }
  bar();
  console.log("Global foo is " + foo);
}());

(function() {
  console.log("Version 2");
  var foo = 1;

  function bar() {
    console.log("At top of bar, foo is " + foo);
    foo = 10;
    console.log("After assignment in bar, foo is " + foo);
    return;
  }
  bar();
  console.log("Global foo is " + foo);
}());




答案 2 :(得分:4)

编写此功能时:

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

javascript读取此内容:

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

函数foo已创建到本地函数bar中。当您编写foo = 10时,您将覆盖本地范围中的函数foo而不是全局变量。

因此,您的警报会给您1,因为您永远不会更新全局变量。

答案 3 :(得分:3)

此处的问题是hoistingclosure

声明function foo(){}被悬挂,意味着在这种情况下,即使它是在函数末尾写的,它也可以在范围内的任何地方使用,包括在它的定义之前。

如果function foo(){}不存在,则语句foo = 10;将覆盖全局范围中定义的foo。因此全球foo === 10

如果存在function foo(){},则语句foo = 10;只会覆盖本地范围内的函数foo,因此全局foo无法触及全局foo === 1 {1}}

var foo = 1;
function bar(){
   console.log(typeof foo) // function      
   return;
   function foo() {}
}
bar();
alert(foo); 

反对:

var foo = 1;
function bar(){
   console.log(typeof foo) // number      
   return;
   // function foo() {}
}
bar();
alert(foo); 

答案 4 :(得分:2)

所以基本上发生的事情就好像你已宣布var foo = 10 因为javascript中的函数声明被提升了 complier看到你的代码如下。

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

所以实际上foo = 10永远不会覆盖全局foo; 它保持在功能的本地。 所以警报将通过全球警报。

答案 5 :(得分:1)

  

除了我在同一个帖子中的 previous answer 之外,我也是   添加另一个答案以提供有关提升的更多详细信息   JavaScript中的功能,因为OP的内容已经接受了上一个答案。

首先让我们对范围界定感到满意

使用JavaScript进行范围界定

JavaScript初学者最困惑的一个原因是范围界定。实际上,它不仅仅是初学者。我遇到了很多经验丰富的JavaScript程序员,他们并不完全了解范围。范围界定在JavaScript中如此混乱的原因是因为它看起来像一个C系列语言。考虑以下C程序:

#include <stdio.h>
int main() {
    int x = 1;
    printf("%d, ", x); // 1
    if (1) {
        int x = 2;
        printf("%d, ", x); // 2
    }
    printf("%d\n", x); // 1
}

此程序的输出将为1,2,1。这是因为C和C系列的其余部分具有块级范围。当控件进入块(例如if语句)时,可以在该范围内声明新变量,而不会影响外部范围。在JavaScript中不是这种情况。在Firebug中尝试以下内容:

var x = 1;
console.log(x); // 1
if (true) {
    var x = 2;
    console.log(x); // 2
}
console.log(x); // 2

在这种情况下,Firebug将显示1,2,2。这是因为JavaScript具有功能级范围。这与C系列完全不同。块(例如if语句)不会创建新范围。只有函数才能创建新范围。

对于许多习惯于C,C ++,C#或Java等语言的程序员来说,这是意料之外的,不受欢迎。幸运的是,由于JavaScript功能的灵活性,有一种解决方法。如果必须在函数中创建临时范围,请执行以下操作:

function foo() {
    var x = 1;
    if (x) {
        (function () {
            var x = 2;
            // some other code
        }());
    }
    // x is still 1.
}

此方法实际上非常灵活,可以在需要临时范围的任何地方使用,而不仅仅在块语句中使用。但是,我强烈建议您花时间真正理解并理解JavaScript范围。它非常强大,是我最喜欢的语言功能之一。如果您了解范围界定,那么吊装将对您更有意义。

声明,姓名和提升

在JavaScript中,名称以四种基本方式之一进入范围:

Language-defined:默认情况下,所有范围都是名称this和arguments。

Formal parameters:函数可以命名形式参数,这些参数的作用域是该函数的主体。

  • 函数声明:它们的格式为function foo() {}
  • 变量声明:其格式为var foo;
  • 函数声明和变量声明总是被JavaScript解释器无形地移动(“提升”)到其包含范围的顶部。
  • 功能参数和语言定义的名称显然已经存在。这意味着代码如下:

例如:

function foo() {
        bar();
        var x = 1;
    }

实际上是这样解释的:

function foo() {
    var x;
    bar();
    x = 1;
}

事实证明,包含声明的行是否会被执行并不重要。以下两个函数是等效的:

function foo() {
    if (false) {
        var x = 1;
    }
    return;
    var y = 1;
}

function foo() {
    var x, y;
    if (false) {
        x = 1;
    }
    return;
    y = 1;
}

请注意,声明的分配部分未被提升。 仅提升名称。函数声明不是这种情况,整个函数体也将被提升。但请记住,声明函数有两种常用方法。请考虑以下JavaScript:

function test() {
    foo(); // TypeError "foo is not a function"
    bar(); // "this will run!"
    var foo = function () { // function expression assigned to local variable 'foo'
        alert("this won't run!");
    }
    function bar() { // function declaration, given the name 'bar'
        alert("this will run!");
    }
}
test();

在这种情况下,只有函数声明将其主体提升到顶部。名称'foo'被悬挂,但身体被遗忘,在执行期间被分配。

这涵盖了吊装的基础知识。此答案完全100%归功于 ben cherry 。我不想在我的回答中发布此链接,因为链接可能会中断,我发现这完全提供了信息,并且必须为任何JavaScript开发人员阅读。