JavaScript的分组操作符如何工作?

时间:2015-05-21 05:30:58

标签: javascript

JavaScript的分组运算符如何工作?

1 + 2;
(1 + 2);

function(){ return 1} + "text";  // SyntaxError
(function(){return 1} + "text");

鉴于上述代码,我有以下问题:

  1. 为什么1 + 2;没有语法错误,而function(){ return 1} + "text"会引发语法错误?
  2. (function(){return 1} + "text")中的分组运算符如何修复语法错误?

4 个答案:

答案 0 :(得分:24)

function位于语句的开头时,它被视为命名函数定义的开头,它应该类似于:

function someName() { return 1; }

这是一个陈述,而不是表达,因此它不能用作更大表达式的一部分。

事实上,没有名字的声明是无效的。您收到语法错误:

function() { return 1}

一个人。

但是当你把它放在括号后面时,它不再是一个语句的开头,所以它是一个函数表达式,它将函数作为一个值返回。然后它可以用作更大表达式中的子表达式。

它不是分组运算符,而是它不在语句的开头。例如,您也可以写:

var foo = function() { return 1 } + "text";

答案 1 :(得分:13)

1+2;在大多数语言中都适用于C语言。 Javascript中允许的一种语句是一个只包含表达式的语句。这是为了允许只包含函数调用的语句,例如foo();或赋值语句,如x=5;。是的,Javascript中的赋值被认为是表达式而不是语句,这就是为什么允许你自己开枪并将一个赋值放在if语句中的条件(经典的= vs == bug) 。最后,编译器很难禁止无用的表达式语句,例如1+2;,同时仍允许foo()x = 5;

function(){} vs (function(){})这是一个Javascript怪癖。 Javascript has different rules in the grammar for "function declaration statements" and "function expressions"。在第一个示例中,函数被解析为语句,不能添加到其他内容中。在第二个中,括号使函数被解析为表达式,这允许将其添加到其他事物中。

这就是"自我调用功能模式"总是在匿名函数中添加一对括号。

(function(){
     ...
 }())

答案 2 :(得分:0)

问题是关于分组运算符()或优先运算符。

初步说明:"函数中使用的括号 [name] (){}"是函数语法的一部分(函数调用的同义词),而不是分组操作符。

分组运算符的优先级高于任何其他运算符,正是因为它的作用是改变其中包含的表达式的优先级(即在括号中)。这意味着括号内的表达式在其值在表达式的其余部分中使用之前已完全求值。此后:

(1+2); // strictly equivalent to 1+2;
       // because nothing more in the expression

或:

var x = ("3"==3)? "ok":"ko"; // grouping operator is useless as well

...但是(正如Barmar'回答中所述): 语法" function(){return 1;}",当置于()之间时,由分组运算符操作,并被视为在完整语句中使用之前要执行的表达式,并且有两个后果:

  1. 允许使用匿名函数,因为我们在函数表达式中;
  2. 要执行,函数表达式必须为其参数提供参数,并且 - 如果您期望返回值(注释2) - 第二对括号是必需的,包含参数或不包含参数。 (function(){return 1;}());
  3. 注2:最初的问题是提到了这个例子:

    (function(){return 1} + "text");  //-> function(){return 1}text
    

    因为没有返回语法错误:它是正确的,但它将函数的代码作为字符串值返回,而不是值1,后跟字符串' text'。为什么?因为没有为执行提供括号。我们应该写:

    (function(){return 1}()) + "text"; //-> 1text
    

答案 3 :(得分:0)

function(){ return 1} + "text";  // SyntaxError

语法错误是由于ECMAScript sepcification期望函数声明必须具有名称这一事实。所以你可以写的是

function foo (){return 1}+"text" // result is NaN

为什么会导致NaN?以上代码相当于以下代码。

function foo(){
    return 1;
}

+"text"

+"text"被视为单独的语句。并且根据ECMAScript规范+运算符在字符串强制它为数字值之后。因此它被解释为Number("text"),其计算结果为NaN。以下是ECMAScript Specification 的链接。

enter image description here

为什么(function(){return 1} + "text")会产生"function(){return 1}text"

分组运算符允许匿名函数,因为函数表达式可以是匿名的。分组操作员强制将其内容作为表达式进行评估。我们知道函数是对象的子类型。因此,遵循加号(+)运算符的规则将适用于此处 -

enter image description here

function_Object + primitive_String => ToPrmitive(function_Object ) + primitive_String 
                                   => (function_Object).toString() + primitive_String
                                   => String_representation_of_function + primitive_String

此处ToPrimitive将调用Function.Prototype.toString() 。它将返回函数的字符串表示形式。然后简单的字符串concativation将产生最终结果。

所以,根据上述规则

(function(){return 1} + "text");

因此,此表达式的结果为"function(){return1}text"