"whats the difference between function foo(){} and foo = function(){}?" 的意思是,“function foo(){}” 和 “foo = function(){}” 有什么区别?
"whats the difference between function foo(){} and foo = function(){}?" 的意思是,“function foo(){}” 和 “foo = function(){}” 有什么区别?
这个问题已经有答案了:
可能重复:
JavaScript:var functionName = function() {} vs function functionName() {}
它们相同吗?我一直在疑惑
不,它们并不相同,尽管它们都会生成一个可以通过符号foo
调用的函数。其中一个是函数声明,另一个是函数表达式。它们在不同的时间进行评估,在定义它们的范围上产生不同的影响,并且在不同的位置上是合法的。
引用我在另一个问题中的回答(为了相关性而进行了编辑),以防那个问题因某种原因被删除(并为了节省人们点击链接的时间):
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会将命名函数表达式处理两次:首先作为函数声明(在进入执行上下文时),然后作为函数表达式,从而在过程中生成两个不同的函数。(真的)。
更多信息请参见:Double take和Named function expressions demystified
注意:下面的内容是在2011年撰写的。在2015年,函数声明在控制块中被添加到语言中,作为ES2015的一部分。它们的语义取决于你是否处于严格模式或松散模式,以及在松散模式下环境是否是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。对于表达式,这不是一个问题,因为它们是在控制流期间完成的。
由于语法无效,实现者可以自由选择执行何种操作。我从未遇到过我所期望的,即抛出语法错误并失败的语法解析器。相反,几乎所有的解析器都会忽略控制流语句,并根据在顶层有两个foo函数声明时应该做什么来处理(这在规范中是使用第二个函数;)。因此,只有第二个foo被使用。Firefox的SpiderMonkey是杰出的,它似乎将它们转换为表达式,因此其使用取决于x的值。Live example。