Possible Duplicates:
What is the difference between a function expression vs declaration in JavaScript?
Explain JavaScript's encapsulated anonymous function syntax
为什么:
1 2 3
| (function () {
//code
}()); |
而这:
1 2 3
| var f = function () {
//code
}(); |
有效,而这:
1 2 3
| function () {
//code
}(); |
不是吗?它看起来完全相同-匿名函数被定义并立即调用。有人能从解释这一点的javascript/ecmascript标准中报价吗?
更新:谢谢大家的回答!关于函数表达式和函数声明。请参阅此堆栈溢出答案、ECMAScript标准第13节和这篇伟大的文章:命名函数表达式已解除定义。
总结答案:
第一个代码段被解释为一个表达式,因为应用了分组运算符()——见ECMAScript标准第11.1.6节。
在第二个代码片段中,函数被解释为表达式,因为它位于赋值运算符=的右侧。
第三个代码段没有任何允许解释器将函数作为表达式读取的内容,因此它被认为是一个声明,没有标识符是无效的(gecko允许它通过,但是它会阻塞后面的()分组运算符(如它认为的)不适用于任何内容)。
- 相关:函数表达式与JavaScript中的声明有什么区别?
- 该帖中已接受的答案链接已断开
- 两个链接对我来说都很好…
- 是的,一定是暂时的故障
- 你的第一个例子也行不通。结束语应为)()而不是())
- @第一个例子很好。外圆括号使它成为一个函数表达式,因此任何一种方法都有效。
- 另请参见:解释javascript的封装匿名函数语法
- 有趣的是,gecko(ff5)允许这样做:function () {}(即匿名声明),而webkit(chrome12)不允许这样做。
前两种情况显示函数表达式,并且可以出现在像(1+1或x*f(4)这样的表达式出现的任何地方。就像1+1对2的计算一样,这些表达式对相应的函数进行计算。
第三种情况是函数声明,可以出现在任何可以有其他语句的地方(如if或while语句)。
尝试通过funcion声明语句声明匿名函数没有多大意义,因为否则之后没有人会得到对该函数的引用。
在前两种情况中,您需要打开(或var x =的原因是它们强制在表达式上下文中解析下一位。(例如,想想你怎么做不到。如果你只是把function作为第一件事,它将被解析为你不想要的声明语句。
- funcion声明语句不能声明匿名函数,否则以后就没有人会得到对该函数的引用。实际上,它可以尝试:function () { }(但是它确实是无用的,因为它既不能就地调用,也不能以其他方式调用)
- 更新:function () { }(即匿名声明)在gecko中有效,但在webkit中无效。
- @ixa:编辑了文章,使之不那么模棱两可。
前两个被称为函数表达式,这意味着它是内联的,并被解释为JS代码运行。
第三个是函数声明,在编译代码时进行解释。因为它是在编译时解释的,所以您不能立即运行它,因为它周围的其他代码都没有运行过。
举例说明:
1 2 3 4 5 6 7 8
| // foo == undefined
// bar == function
function bar(){ .. }
var foo = function(){ ... }
// foo == function
// bar == function |
简单地说,任何时候如果你有一个单词function,前面没有任何内容,它就是一个声明。任何时候在它之前,它都是一种表达。
- @彼得莫滕森——世贸组织?不要对随机文章进行毫无意义的编辑。
这里有一个简单的方法来考虑它:如果function是行中的第一个关键字,解析器将把行中的其余部分解释为函数声明。换言之,它会认为您正试图写这样的东西,好像您忘记了命名您的函数:
1 2 3
| function foo(){
// code
} |
解决这个问题的方法是要么将整个函数包装在一些parens中,要么将其作为变量赋值的一部分。在这两种情况下,您都将function放回行中,并允许解析器识别您没有在编写函数声明。
允许function出现在一行的开头,并且仍然区分函数表达式和函数声明,这对我来说似乎是微不足道的,但我猜在最初设计JavaScript时,这并不是那么微不足道。
- 回复:你的最后一段;根本没有理由让这个边缘案例的语言语法复杂化。你为什么需要这个?
- @Tomalak Geret'kal,一个(尽管有疑问)原因:它会被考虑,即,如果没有标识符的任何东西被解释为表达式(因为没有标识符的声明无论如何都是无用的)。
- @ Ixa:的确如此。也许更为一致,但有疑问的好处,那为什么要把语法复杂化呢?
- @Tomalak Geret'kal,我个人认为语言设计者从来没有预料到会自动执行匿名函数,所以我在这里没有发现任何错误。但是我认为他们要求你在parens中包装自己执行的匿名函数,这使得语法更加复杂。使用for迭代数组和对象(而不是创建foreach)的事实表明,它们在这里也可以使用灵活性。当它在语法上与声明有区别时,为什么要抛出异常呢?这让我很烦。
- @安德鲁:他们什么都不需要。你不会被迫使用那种可怕的语法。
- @托马拉克·杰瑞特·卡尔,听起来你不喜欢那种风格。虽然我不明白这和这个问题有什么关系,但我对这个没有问题。但是有人在这里需要一些东西,如果这样做会导致语法错误。此外,在阅读了ecma 262的相关部分之后,我实际上找不到任何地方可以说您不能用函数表达式开始一行。正如@ixa所观察到的,这实际上是一个浏览器实现问题,而不是JS语法问题。
- @安德鲁:这是语法固有的。如果此语法生成函数声明,那么它也不能生成函数表达式。
- @Tomalak Geret'ka,那为什么它在FF工作?阅读ECMA规范。function(){/*code*/}是一个表达式。function identifier(){}是一种声明。同样,for(exp1;exp2;exp3){/*code*/}迭代数组的元素。for(exp) {/*code*/}迭代对象的成员。这里没有歧义,因为语句有不同的签名。
在堆栈溢出中很好地解释了匿名函数问:为什么需要在同一行上调用匿名函数?.