为什么需要JavaScript函数声明(和表达式)?

16

我看到其他人使用了以下模式。

var bar = function foo(){};
console.log(bar); // foo()
console.log(foo); // ReferenceError: foo is not defined

但为什么呢?如果两者都被声明了,我可以理解,但它们并没有。原因是什么?


3
你那里有一个具有名称的匿名函数。我知道这样做的唯一原因是,当你调试foo()函数时,堆栈跟踪将显示该名称,而不仅仅是“匿名函数”。 - Ben Clayton
@BenClayton的“具有名称的匿名函数”是一个矛盾之词。它是一种命名函数表达式。 - Sebastian Simon
5个回答

8
正如其他人所提到的,在您的示例中使用第一种形式(命名函数表达式)可以帮助调试,尽管随着浏览器内置开发工具的最新改进,这个论点变得不那么有说服力了。使用命名函数表达式的另一个原因是,您可以在函数体内使用函数名称作为变量,而不是现在已弃用的ES5中的“arguments.callee”。

然而,在Internet Explorer < 9中,命名函数表达式被错误地和有问题地实现,应该在针对这些浏览器时避免使用。有关更多信息,请参见Juriy Zaytsev的优秀文章

在内部作用域中提及函数名称的可见性,加1分。 - Fabrizio Calderan
在 Mozilla 的官方文档中,我们可以看到 "+1" 这个函数名称只能在函数体内使用。请参考此链接:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions#Differences - Adriano

7

当调试应用程序时,如果使用"命名"匿名函数,可以更容易地了解调用堆栈中的内容。因此,这是为了调试目的给匿名函数赋予名称的一种方式。

尝试这个并在调试器中查看调用堆栈:

myDiv = document.getElementById("myDiv");

myDiv.onclick = function OnClick(){
    debugger;
    //do something
}

4
谨慎在 IE < 9 中使用命名函数表达式:这些浏览器的实现存在错误。http://kangax.github.com/nfe/ - Tim Down
更具体地说,在早期版本的IE中,将函数分配给onclick属性是有问题的,而不是语法function OnClick() {}。 - Zoidberg
1
@Zoidberg:不,那不是我的意思。在IE < 9中,语法var foo = function bar() {};本身肯定是有问题的。此外,DOM0事件处理程序属性(例如myDiv.onclick = function() {};)在IE中可以正常工作。我想你可能在考虑setAttribute()(例如myDiv.setAttribute("onclick", "alert('click')");),这在旧版IE中确实存在问题。 - Tim Down
我在IE 8及更早版本中使用了function(){}函数,并且它对我来说完全正常工作。如果它不能编译,请详细说明出现了什么错误。 - Zoidberg
2
@Zoidberg:所有细节都在我链接的文章中(http://kangax.github.com/nfe/)。虽然它通常可以工作,但问题很微妙,这意味着它可能会导致难以发现的错误。 - Tim Down
@TimDown 我刚刚注意到语法上的差异。var foo = function bar() {},我以为你是指 var foo = function () {}(没有bar)。我以前从未使用过 var foo = function bar() {} 这种语法,也从未有过这种需要。感谢您提醒我。如果他将其更改为 myDiv.onclick = function () {..},它不会在IE 8及以下版本中出现问题。 - Zoidberg

2
我能想到的唯一原因是为函数取一个期望的名称。这有助于调试,因为检查器使用函数对象的name属性。请尝试此操作:
var bar = function foo(){};
console.log(bar.name); // foo

如果你在foo函数中加入一些实际的代码,并在浏览器的JavaScript调试器中添加断点,你将会在调用栈中看到该函数名为foo


2

他们给一个匿名函数命名是因为这样更容易调试。在调试时,你会看到调用堆栈中的“foo”而不是一堆“anonymous”的调用。


0

函数定义(或文字)由4个部分组成。1.保留字function 2.可选名称,调试器或函数可以使用它来递归调用自身。3.参数和4.函数体,由{ }包装。

在函数范围之外,foo不存在。但是,由于将函数分配给变量bar,因此可以使用方法调用bar调用它,并且由于定义了bar,因此可以打印它。

如果您对JavaScript感兴趣,真的应该考虑获取Douglas Crockford的书Javascript:The Good Parts


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