为什么我的JavaScript函数名称会发生​​冲突?

时间:2014-05-27 12:21:27

标签: javascript function

我写了下面的脚本,看看当一个变量和一个分配了函数的函数的名字发生碰撞时会发生什么:

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

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

f();

我得到的输出是“我原创”。为什么没有调用其他函数?

另外,如果我将原始作业更改为var f = new function() {,则会显示“我原创”,然后是类型错误object is not a function。有人可以解释一下吗?

3 个答案:

答案 0 :(得分:171)

在JavaScript中提升函数声明(移到顶部)。虽然在解析顺序方面不正确,但由于函数声明被挂起,因此您所拥有的代码在语义上与以下相同:

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();

反过来,由于可变吊装与以下相同:

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

f();

哪个解释了你得到了什么,你重写了这个功能。更一般地说,JavaScript中允许多个var声明 - var x = 3; var x = 5完全合法。在新的ECMAScript 6标准中,let语句禁止这样做。

@kangax的

This article在揭开javascript中的功能方面做得非常出色

答案 1 :(得分:10)

如果看起来没有人回答您的后续问题,那么我会在此回答,但您通常应该将后续问题作为单独的问题提出。

你问为什么:

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();

由于本杰明解释的功能提升,上述内容基本上与此相同:

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

f = new myConstructor();

f();

这个表达式:

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

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

f();

您收到错误,因为f不是函数。

答案 2 :(得分:2)

请原谅我,如果这是一种接近添加点的错误方法。我不是一直在这里,并欢迎建设性的指导和/或批评。

本杰明的回答很好地解决了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() {...构造中使用的函数表达式不会被提升。

所以在吊装之后,执行就好像代码是:

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字的东西。