当我定义Foo时,为什么Foo不是一个函数?

时间:2015-12-29 00:32:35

标签: javascript

我猜这是某种“范围”问题,但我想理解为什么会这样。

function foo(){
  return true;
}

function bar(){
  var foo = foo();
  console.log(foo);
}

var foo = foo();
console.log(foo); //returns true as expected

但是,当我做以下

function foo(){
  return true;
}

function bar(){
  var foo = foo();
  console.log(foo);
}

bar(); //returns Uncaught TypeError: foo is not a function

似乎变量名称不能与函数名称相同。但这不是真的吗?

3 个答案:

答案 0 :(得分:4)

有两个概念可以帮助您理解这一点:

第一个是阴影,这意味着如果在范围内定义变量名称,它将隐藏父范围内的相同变量名称(或函数名称)。

第二个是提升,这会导致任何变量声明移动到本地范围的顶部。

此代码

function foo(){}

function bar(){
  var foo = foo();
  console.log(foo);
}

等同于此

var foo;//will initialize foo to undefined
foo = function(){}

var bar;
bar = function(){
  var foo;//will shadow parent foo and initialize foo to undefined
  foo = foo(); //fails because you are trying to call an undefined object
  console.log(foo);
}

希望,这很明显为什么'foo不是一个函数'。你的bar函数声明了一个新的foo变量(隐藏了bar范围内的全局变量),然后通过调用自身来尝试分配这个变量。

您可以在此处详细了解var的错综复杂信息:

https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Statements/var

答案 1 :(得分:1)

在JavaScript中,函数声明(如foo声明)创建的名称与变量非常相似。因此,您的第二个示例失败的原因与此示例警告2而不是1:

的原因相同
var a = 1;
function bar() {
    var a = 2;
    alert(a);
}

...因为a 阴影内的bar a以外的bar barbar以来一直在范围内关闭它。

  

似乎变量名称不能与函数名称相同。但这不是真的吗?

变量名称确实可以与函数名称相同,但如果您在嵌套作用域中执行此操作(如您所愿),则变量名称​​ shadow 函数名称。

function bar(){ var foo = foo(); console.log(foo); }

foo

... foo()中的barundefined中声明的变量,而不是外部作用域中声明的函数。因此,它具有默认值变量(var foo),无法调用,因此您会收到错误。

在评论中你问过:

  

因为我在第二个例子中覆盖了foo,所以我不是在第一个例子中覆盖它吗?

不,这将我们带回到上面的第一个语句:函数声明创建的名称非常类似于变量。因此,如果声明一个函数,然后稍后声明一个具有相同名称的变量,则忽略变量声明。因此,您的第一个示例被解释为在全局范围内根本没有var foo = foo();。所以foo = foo()真的是foo,它运行得很好,调用foo然后使用返回值来更新{{1}}。 (再次执行会失败,因为函数返回的值不可调用。)

答案 2 :(得分:0)

检查代码上的推荐

function foo(){
  return true;
}

function bar(){
  var foo = foo(); // before calling foo(), foo is defined as a variable, so foo is not a function anymore in this scope.
  console.log(foo);
}

bar(); //returns Uncaught TypeError: foo is not a function