20

How does JavaScript's grouping operator work?

1 + 2;
(1 + 2);

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

Given the above code, I have the following questions:

  1. Why does 1 + 2; work without syntax error, whereas function(){ return 1} + "text" raises a SyntaxError?
  2. How does the grouping operator in (function(){return 1} + "text") fix the syntax error?
Badacadabra
  • 8,043
  • 7
  • 28
  • 49
jobin
  • 1,119
  • 2
  • 12
  • 22
  • possible duplicate of [Explain JavaScript's encapsulated anonymous function syntax](http://stackoverflow.com/q/1634268/1048572) – Bergi May 21 '15 at 13:59

4 Answers4

29

When function is at the beginning of a statement, it's treated as the beginning of a named function definition, which should be like:

function someName() { return 1; }

This is a statement, not an expression, so it can't be used as part of a larger expression.

In fact, it's not valid to have that statement without a name. You get a syntax error from:

function() { return 1}

all by itself.

But when you put it after a parenthesis, it's not the beginning of a statement any more, so it's a function expression, which returns the function as a value. Then it can be used as a sub-expression in a larger expression.

It's not the grouping operator that does it, just the fact that it's not at the beginning of the statement. For instance, you can also write:

var foo = function() { return 1 } + "text";
Barmar
  • 741,623
  • 53
  • 500
  • 612
  • is "1 + 2;" an expression or statement?, is "function() {}" an expression or statement?, I'm asking because i found this whiten ecmascript spec: The production PrimaryExpression : ( Expression ) is evaluated as follows:http://www.ecma-international.org/ecma-262/5.1/#sec-11.1.6 – jobin May 21 '15 at 08:39
  • 1
    `1+2` is an expression. `1+2;` is an [ExpressionStatement](http://www.ecma-international.org/ecma-262/5.1/#sec-12); a statement containing a single expression. – hugomg May 21 '15 at 12:46
  • 2
    @jobin Any expression can be used as a statement, but not the other way around. For instance, you can't write `(var a = 3) + 4` because `var a = 3` is a statement, but not an expression. – Barmar May 21 '15 at 14:19
16

The 1+2; is something that works in most languages with a C-inspired syntax. One of the kinds of allowed statements in Javascript is a statement that just contains an expression. This is to allow statements that just contain a function call, such as foo(); or assignment statements like x=5;. Yes, assignments in Javascript are considered expressions instead of statements, which is why you are allowed to shoot yourself in the foot and put an assignment inside an if-statement conditional (the classic = vs == bug). In the end, it would be hard for the compiler to forbid useless expression-statements such as 1+2; while still allowing foo() and x = 5;.

The function(){} vs (function(){}) thing is a Javascript quirk. Javascript has different rules in the grammar for "function declaration statements" and "function expressions". In the first example the function is parsed as a statement, which cannot be added to other things. In the second, the parenthesis makes the function be parsed as an expression, which allows it to be added to other things.

This is why the "self invoking function pattern" always adds a pair of parenthesis arounf the anonymous function.

(function(){
     ...
 }())
Community
  • 1
  • 1
hugomg
  • 68,213
  • 24
  • 160
  • 246
2

The question is about the grouping operator (), or precedence operator.

Preliminary note: parenthesis used in "function [name](){}" are part of the syntax of the function (idem for function invokation), not a grouping operator.

The grouping operator has the highest precedence over any other operator, precisely because its role is to alter the precedence of the expression contained in it (i.e. in parenthesis). This means that the expression within parenthesis is fully evaluated before its value is used in the remainder of the expression. Henceforth:

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

or:

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

... but (as stated in Barmar'answer): the syntax "function(){return 1;}", when put between (), is operated by the grouping operator, and is considered as an expression to be executed before being used in the full statement, and there are 2 consequences:

  1. an anonymous function is allowed, for we are in a function expression;
  2. to be executed, a function expression must have arguments provided to its parameters, and -if you are expecting the return value(note2)- a second pair of parenthesis is mandatory, to contain the arguments, or no argument. (function(){return 1;}());

Note2: the original question was mentioning the example:

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

as not returning a Syntax Error: it's correct, but it returns the code of the function as a string value, not the value 1, followed by the string 'text'. Why? because no parenthesis were provided for the execution. We should rather write:

(function(){return 1}()) + "text"; //-> 1text
allez l'OM
  • 547
  • 4
  • 13
1
function(){ return 1} + "text";  // SyntaxError

The syntax error is due to the fact that, ECMAScript sepcification expect that a function declaration must have a name.So what you could write is

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

Why it results in NaN ? Becaluse the above code is equivalent to the following.

function foo(){
    return 1;
}

+"text"

the +"text" is read as separate statement. And according to ECMAScript specification + operator before a string coerce it to be a Numeric value.So it is interpreted as Number("text"), which evaluates to NaN. Here is the link to ECMAScript Specification .

enter image description here

Why (function(){return 1} + "text") results in "function(){return 1}text" ?

The grouping operator allows anonymous function as function expressions can be unanonymous. Grouping operator force it's content to be evaluated as an expression.We know that function is a subtype of object. So following rule of plus(+) which is also known as concatination operator will apply here --

enter image description here

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

Here ToPrimitive will call Function.Prototype.toString() .It will return string representation of the function. Then simple string concativation will take palce to produce the final result.

So, according to the above rule

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

So the result of this expression will be "function(){return1}text"

AL-zami
  • 8,902
  • 15
  • 71
  • 130