为什么变量声明总是可以覆盖函数声明?

7
无论我是在变量之前还是之后定义函数
var a = 1;
function a() {};
typeof a // number

或者,如果我在变量之前定义函数。
function a() {};
var a = 1;
typeof a // number

最终的typeof结果始终为number

我在http://davidshariff.com/blog/what-is-the-execution-context-in-javascript/中找到了一些关于执行上下文的解释。

Before executing the function code, create the execution context.
......
Scan the context for variable declarations:
If the variable name already exists in the variable object, do nothing and continue scanning.

但是这似乎没有效果。

那么我该如何解释呢?


2
尝试运行 var a = function(){}; 并查看 typeof 返回的结果。 - asawyer
JavaScript的解析/评估顺序是什么? - Andreas
1
函数a(){}在作用域中的变量之前总是被提升,因此a的最新类型始终为数字。这就是为什么在“现代”JavaScript中最好将命名函数声明为var a=function(){}的原因。 - mpm
3个回答

5

这与JavaScript的变量提升有关。请尝试使用以下内容替换:

var a = 1;
var a = function() {};
typeof a // function

1
您使用函数语句“function a(){};”多次隐式声明变量,正如其他人指出的那样,这会将变量提升并由于浏览器注册申明的顺序而导致行为异常。在幕后,此语句实例化一个函数对象并将结果分配给作为函数名称传递的变量(reference),但是在执行显式var声明之前进行此操作,从而覆盖了隐式声明。如果只做以下操作,它将更直观:
var a = 1;
a = function(){};
console.log(typeof a);  // function

这个选项从逻辑上来说比其他答案中的多个变量声明更好,因为(尽管你可以),重复声明变量并不是一个好习惯。
具体回答这个问题的原因是:这样可以使用这些语句定义函数并在显式声明中使用它们,比如
var a = someFunction();  
function someFunction(){ return 'someVal'; }

如果函数语句没有被首先解析和提升,这是不可能的。

1

如前所述,这与JavaScript提升的工作方式有关。需要注意的主要问题是JavaScript会将完整的函数定义(包括函数体)提升到顶部,但仅保留变量初始化在其原本位置(只有声明被提升)。

因此,如果你写了这样的代码:

var a = 1;
function a () {
}

它将被翻译为:

它将被翻译为:

var a;
function a() {
}
a = 1;

如果你写下这个:

function a () {
}
var a = 1;

它将被翻译为:

function a () {
}
var a;
a = 1;

无论你做什么,a = 1;都会保持在最底部。
请注意,上述“翻译”应理论上看待。如果已经有一个同名的函数声明,JavaScript可能有一种方法省略var a;语句。还可能有一个定义好的顺序(函数在变量之前提升或反之亦然)。但所有这些都不影响变量初始化是唯一不被提升的部分的结果。

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