可以在JavaScript中的语句内部显示函数声明吗?

时间:2010-11-01 17:16:18

标签: javascript

请将官方ECMAScript规范视为您的答案来源,而不是特定浏览器供应商发布的文档。 (我知道Mozilla用“函数语句”扩展了它的JavaScript实现。)

那么,根据ECMAScript规范,ergo,其中定义的句法产品,是否有效?

if (foo) {
    function x() { return; }
}

更新: 我的问题也可以这样说: Statement 生产是否包含 FunctionDeclaration 生产?

结论: 答案是否定的。

7 个答案:

答案 0 :(得分:20)

我不同意其他有效的答案。

根据ECMA-262 5th Edition specificationBlocks只能包含StatementsSection 12.1):

Block :
   { StatementList opt }

StatementList :
   Statement
   StatementList  Statement

但是规范没有定义函数语句,只有FunctionDeclarationFunctionExpression。该规范进一步在Section 12中对此进行了说明:

  

已知几种广泛使用的ECMAScript实现支持将FunctionDeclaration用作Statement。然而,在应用于此类FunctionDeclarations的语义中的实现之间存在显着且不可调和的变化。由于这些不可调和的差异,使用FunctionDeclaration作为Statement会导致代码在实现中无法可靠地移植。建议ECMAScript实现不允许使用FunctionDeclaration或在遇到此类用法时发出警告。 ECMAScript的未来版本可以定义用于在Statement上下文中声明函数的替代可移植方法。

如需进一步阅读,您可能还有兴趣查看comp.lang.javascript FAQ Section 4.2

  

4.2什么是函数语句?

     

术语函数语句被广泛而错误地用于描述FunctionDeclaration。这是误导性的,因为在ECMAScript中,FunctionDeclaration不是Statement;程序中有些地方允许StatementFunctionDeclaration不允许。为了增加这种混淆,一些实现,特别是Mozillas',提供了一种称为函数语句的语法扩展。 ECMA-262第3版和第5版第16节允许这样做。

     

非标准函数声明示例:

// Nonstandard syntax, found in GMail source code. DO NOT USE.
try {
  // FunctionDeclaration not allowed in Block.
  function Fze(b,a){return b.unselectable=a}
  /*...*/
} catch(e) { _DumpException(e) }
     

使用函数语句的代码有三种已知的解释。有些实现按顺序处理Fze作为语句。其他人,包括JScript,在进入它出现的执行上下文时评估Fze。还有一些,特别是DMDScript和BESEN的默认配置,抛出SyntaxError

     

对于跨实现的一致行为,不要使用函数语句;请改用FunctionExpressionFunctionDeclaration

     

FunctionExpression示例(有效):

var Fze;
try {
  Fze = function(b,a){return b.unselectable=a};
  /*...*/
} catch(e) { _DumpException(e) }
     

FunctionDeclaration示例(有效):

// Program code
function aa(b,a){return b.unselectable=a}

答案 1 :(得分:3)

我不知道如何阅读本文,但ECMA-262 V5有这样的说法:

  

注意已知几种广泛使用的ECMAScript实现支持使用FunctionDeclaration作为语句。然而,在应用于此类FunctionDeclarations的语义中的实现之间存在显着且不可调和的变化。由于这些不可调和的差异,使用FunctionDeclaration作为Statement会导致代码在实现中无法可靠地移植。建议ECMAScript实现不允许使用FunctionDeclaration,或在遇到此类用法时发出警告。 ECMAScript的未来版本可以定义用于在Statement上下文中声明函数的替代可移植方法。

如果我理解正确,严格来说,这意味着函数声明根本不能在块内,因为块只能包含语句。

我的解释可能完全错误 - 但我不熟悉ECMAScript的内部工作原理。

答案 2 :(得分:3)

不,它无效。函数声明只能作为“源元素”出现,它们位于全局范围内,或者在另一个函数定义中,在所有其他语句之外。来自ECMA-262规范:

  

FunctionBody:SourceElements

     

计划:SourceElements

     

SourceElement:Statement | FunctionDeclaration

语法中没有其他产品允许FunctionDeclaration

只允许函数表达式成为语句的一部分:

  

MemberExpression:FunctionExpression

     

...

     

声明:ExpressionStatement

编辑:最近有关于另一个问题的相关讨论。请参阅this answer上的评论 - 之前,我也认为此可以有效,但语法清楚表明它无效。

答案 3 :(得分:2)

From ECMA 262 chapter 14

  
      
  1. 程序语法
  2.         

    计划:SourceElements   SourceElements:SourceElement   SourceElements SourceElement   SourceElement:Statement   FunctionDeclaration Semantics

         

    制作计划:   SourceElements评估为   如下:

         
        
    1. 处理函数声明的SourceElements。

    2.   
    3. 评估SourceElements。

    4.   
    5. 返回结果(2)。

    6.         

      生产SourceElements:   处理SourceElement   函数声明如下:

           
          
      1. 处理函数声明的SourceElement。
      2.         

        生产SourceElements:   SourceElement的评估如下:

             
            
        1. 评估SourceElement。

        2.   
        3. 返回结果(1)。

        4.         

          生产SourceElements:   SourceElements SourceElement是   处理函数声明为   如下:

               
              
          1. 处理函数声明的SourceElements。

          2.   
          3. 处理函数声明的SourceElement。

          4.         

            生产SourceElements:   SourceElements SourceElement是   评估如下:

                 
                
            1. 评估SourceElements。

            2.   
            3. 如果结果(1)突然完成,则返回结果(1)

            4.   
            5. 评估SourceElement。

            6.   
            7. 返回结果(3)。

            8.         

              制作SourceElement:   * 语句处理功能 *   声明,不采取任何行动。

                   

              制作SourceElement:   * 声明评估如下: *

                   

              <强> 1。评估声明。

                   

              <强> 2。返回结果(1)。

                   

              生产SourceElement:   处理FunctionDeclaration   函数声明如下:

                   
                  
              1. 函数声明的Process FunctionDeclaration(见第13节)。
              2.         

                生产SourceElement:   FunctionDeclaration评估为   如下:

                     
                    
                1. 返回(正常,空,空)。
                2.   

芒果正式没有。 (ŠimeVidas在另一个问题上让我很难相信)

但是没有指定Exception,因此根据浏览器的实现,它会失败或无声地工作。

答案 4 :(得分:1)

ECMA-262的第5版说它不应该有效:

  

仅允许使用FunctionDeclarations   出现在Program或FunctionBody中。   从语法上讲,它们不能出现在   阻止({...}) - 如if,   而对于陈述。这是   因为块只能包含   声明,而不是SourceElements,其中   FunctionDeclaration是。如果我们看一下   仔细制作规则,我们可以看到   这是Expression的唯一方式   Block内允许的时间是   ExpressionStatement的一部分。然而,   ExpressionStatement是显式的   定义为不以“功能”开头   关键字,这正是如此   使FunctionExpression无效为   声明或块的一部分(注意   那个Block只是一个列表   语句)。

但是,似乎没有多少口译员遵守这一规则。 Kangax说他们应该被视为每this page的语法错误:

  

由于这些限制,   每当函数出现在块中时   (例如在前面的例子中)它   应该被认为是一种语法   错误,不是函数声明或   表达。问题是差不多   没有我见过的任何实现   严格解析这些功能   规则(例外是BESEN和   DMDScript)。他们解释他们   专有的方式。

答案 5 :(得分:0)

在ECMAScript标准中,FunctionDeclaration未定义为Statement,并且Statement未定义为能够包含FunctionDeclaration,因此它们根据标准不兼容(尽管实际上每个JavaScript解释器都会尝试做某事是明智的,尽管实现之间并不一致。)

答案 6 :(得分:-1)

是的,它是有效的。

所有语句块(即花括号内的所有内容)都可以包含其他语句和声明,包括函数。

所以你也可以在函数中定义函数等等

这是ECMA-262 v1 - http://www.mozilla.org/js/language/E262.pdf