函数foo(){}和foo = function(){}之间的区别是什么?

时间:2011-03-23 09:29:07

标签: javascript functional-programming

  

可能重复:
  JavaScript: var functionName = function() {} vs function functionName() {}

它们是一样的吗?我一直想知道

2 个答案:

答案 0 :(得分:31)

不,它们不一样,虽然它们都会产生一个可以通过符号foo调用的功能。一个是函数声明,另一个是函数表达式。它们在不同的时间进行评估,对它们的定义范围产生不同的影响,并且在不同的地方是合法的。

在这里引用my answer to this other question(编辑了一点相关性),以防其他问题因某种原因被删除(以及保存链接后的人):


JavaScript有两个不同但相关的东西:函数声明和函数表达式。它们之间存在显着差异:

这是一个函数声明

function foo() {
    // ...
}

在执行任何分步代码之前,在进入封闭范围时评估函数声明。函数的名称(foo)被添加到封闭范围(从技术上讲,变量对象用于执行上下文,函数定义在其中)。

这是一个函数表达式(具体来说,是一个匿名的,就像你引用的代码一样):

var foo = function() {
    // ...
};

函数表达式作为逐步代码的一部分进行评估,在它们出现的位置(就像任何其他表达式一样)。那个创建一个没有名称的函数,它分配给foo变量。

函数表达式也可以命名为而不是匿名。命名的一个看起来像这样:

var x = function foo() {  // Valid, but don't do it; see details below 
    // ...
};

根据规范,命名函数表达式有效。它应该创建一个名为foo的函数,但foo放入封闭范围,然后将该函数分配给x变量(全部在逐步代码中遇到表达式时会发生这种情况。当我说它不应该将foo放在封闭的范围内时,我的意思是:

var x = function foo() {
    alert(typeof foo); // alerts "function" (in compliant implementations)
};
alert(typeof foo);     // alerts "undefined" (in compliant implementations)

请注意,这与函数声明的工作方式有何不同(函数的名称 添加到封闭范围内)。

命名函数表达式适用于兼容的实现,但在野外实现中曾经存在多个错误,尤其是Internet Explorer 8及更早版本(以及Safari的早期版本)。 IE8处理命名函数expresssion 两次:首先作为函数声明(在进入执行上下文时),然后作为函数表达式 ,在过程中产生两个不同的功能。 (真)。

更多信息:Double take和此处:Named function expressions demystified


注意:以下是2011年编写的。2015年,控制块中的函数声明作为ECMAScript 2015的一部分添加到语言中。它们的语义因您是严格还是严格而有所不同松散模式,如果环境是Web浏览器,则处于松散模式。当然,关于您使用的环境是否正确支持ES2015的定义。 (令我惊讶的是,在2017年7月的撰写中,Babel也没有正确地将它们转换为。)因此,在特定情况下,你只能在控制流结构中可靠地使用函数声明,所以它仍然可能现在,最好使用函数表达式。

最后,他们之间的另一个区别是他们是合法的。函数表达式可以出现在表达式可以出现的任何地方(几乎在任何地方)。函数声明只能出现在其封闭范围的顶层,在任何控制流语句之外。例如,这是有效的:

function bar(x) {
    var foo;

    if (x) {
        foo = function() {  // Function expression...
            // Do X
        };
    }
    else {
        foo = function() {  // ...and therefore legal
            // Do Y
        };
    }
    foo();
}

...但事实并非如此,并且不会执行它在大多数实现中所做的事情:

function bar(x) {

    if (x) {
        function foo() {  // Function declaration -- INVALID
            // Do X
        }
    }
    else {
        function foo() {  // INVALID
            // Do Y
        }
    }
    foo();
}

它非常有意义:因为foo函数声明在进入bar函数时被评估,所以在执行任何逐步代码之前,解释器不知道哪个foo函数1}}来评估。这对表达式来说不是问题,因为它们是在控制流程中完成的。

由于语法无效,实现可以自由地执行他们想要的操作。我从来没有遇到过一个能达到预期效果的,就是抛出语法错误而失败。相反,几乎所有这些都忽略了控制流语句,并且如果在顶层有两个foo函数声明(使用第二个;在规范中),它们应该做什么。所以只使用第二个foo。 Firefox的SpiderMonkey是杰出的,它似乎(有效地)将它们转换为表达式,因此它使用取决于x的值。 Live example

答案 1 :(得分:1)

我在提出非常相似的问题时得到了很好的解释:Two functions with the same name in JavaScript - how can this work?