为什么我的JavaScript函数名称冲突?

我只写了下面的脚本来看看当一个variables和一个函数分配给它的函数的名字冲突时会发生什么:

var f = function() { console.log("Me original."); } function f() { console.log("Me duplicate."); } f(); 

我得到的输出是“我原来的”。 为什么另一个函数不被调用?

另外,如果我改变我原来的赋值为var f = new function() { ,我得到“我原来的”,后面跟着一个TypeError说object is not a function 。 有人可以解释吗?

函数声明在JavaScript中被提升(移动到顶部)。 虽然在parsing顺序方面不正确,但由于函数声明是悬而未决的,因此您的代码在语义上与以下内容相同:

 function f() { console.log("Me duplicate."); } var f = function() { console.log("Me original."); } f(); 

反过来,除了函数的名字是一样的:

 var f = function() { console.log("Me duplicate."); } var f = function() { console.log("Me original."); } f(); 

而由于variables提升又是这样的:

 var f; f = function() { console.log("Me duplicate."); } f = function() { console.log("Me original."); } f(); 

这解释了你所得到的,你重写了这个函数。 更一般地说,在JavaScript中允许多个var声明 – var x = 3; var x = 5 var x = 3; var x = 5是完全合法的。 在新的ECMAScript 6标准中, let声明禁止这个。

这篇由@kangax撰写的文章在javascript中揭开了function的神秘面纱

如果看起来没有人回答你的后续问题,所以我会在这里回答,尽pipe你通常应该提出后续问题作为单独的问题。

你问为什么这样:

 var f = new function() { console.log("Me original."); } function f() { console.log("Me duplicate."); } f(); 

打印出“我原来的”。 然后出错。

这里发生的事情是, new的函数将被用作构造函数。 所以这相当于以下内容:

 function myConstructor() { console.log("Me original."); } var f = new myConstructor(); function f() { console.log("Me duplicate."); } f(); 

由于本杰明解释的function提升,以上基本相当于:

 var myConstructor = function() { console.log("Me original."); }; var f = function() { console.log("Me duplicate."); }; f = new myConstructor(); f(); 

这个expression式:

 var f = new function() { console.log("Me original."); } 

导致一个新的对象被构​​造并赋值给f ,使用匿名函数作为构造函数。 “我原来的。” 在构造函数执行时被打印出来。 但是构造的对象本身并不是一个函数,所以当它最终执行时:

 f(); 

你会得到一个错误,因为f不是一个函数。

原谅我,如果这是错误的方法来添加一个点。 我一直没有到这里来,并会欢迎build设性的方向和/或批评。

本杰明的回答非常好地解决了OP的问题,但是我想补充一点,可以让我们全面地了解这个问题以及它的古怪之处。

如果我们通过调用f来启动原始代码,如下所示:

 f(); var f = function() { console.log("Me original."); }; function f() { console.log("Me duplicate."); } f(); 

输出将是:

 Me duplicate. Me original. 

原因是varfunction声明略有不同。

对于var 声明移动到当前作用域*的顶部,但是任何赋值都不会被挂起。 至于声明的var的值,直到达到原来的赋值行才定义。

对于function 语句 ,声明定义都被挂起。 在var f = function() {...构造中使用的函数expression式不会被挂起。

所以在提出之后,执行就好像代码是:

 var f; // declares var f, but does not assign it. // name and define function f, shadowing the variable function f() { console.log("Me duplicate."); } // call the currently defined function f f(); // assigns the result of a function expression to the var f, // which shadows the hoisted function definition once past this point lexically f = function() { console.log("Me original."); } // calls the function referenced by the var f f(); 

*所有的JavaScript作用域都是词法,或者是函数,范围,但是似乎只是混淆了那些使用f这个词的东西。