42

Here is the jsfiddle

The full code:

function foo1(){
    return {msg: "hello1"};
}
function foo2(){
    return
    {msg: "hello2"};
}

// output = "foo1 =  {"msg":"hello1"}"
console.log('foo1 = ' , JSON.stringify(foo1())); 

//output = " foo2 =  undefined "
console.log('foo2 = ' , JSON.stringify(foo2()));

The difference between the two is that in foo2, the {msg: 'hello'} is in its own new line. I was expecting the parser to ignore whitespaces?

dchhetri
  • 6,926
  • 4
  • 43
  • 56
  • 2
    not with a return statement I do believe, I remember reading it somewhere that this is one of the rare cases in JS that the whitespace does matter. Possible duplicate http://stackoverflow.com/questions/8528557/a-return-statement-in-javascript-does-not-work-properly-if-the-return-value-is – OJay Aug 14 '13 at 01:52
  • Check this link: http://robertnyman.com/2008/10/16/beware-of-javascript-semicolon-insertion/ – Akhil Sekharan Aug 14 '13 at 01:53
  • Certain whitespace. Any number of normal ASCII spaces are fine, whereas not a single LF/CR is permitted. Seems arbitrary, but I'm going to assume there's a logical explanation for why I lost an hour on this matter last night. The linter's error message could have been more exact/helpful.... – Shon Jun 02 '15 at 16:01

2 Answers2

44

tl;dr The line break is causing the 'undefined' in the second function. JavaScript doesn't require semicolons in a lot of cases and just assumes them in certain contexts (Automatic Semicolon Insertion).


In certain cases, to avoid this ASI problem and for aesthetic reasons, I use the so-called grouping operator. For example, with the hoquet templating DSL (it compiles Arrays as s-expressions into HTML), I like to group the Arrays so that they clearly show the HTML structure:

return (
  ["ul"
  , ["li"
    , ["span", {class: "name"}, this.name]
    , ["span", {id: "x"}, "x"]
    ]
  ]
);

which seems somewhat clearer, or more consistent to me than

return [
  "ul",
  [
    "li",
    ["span", {class: "name"}, this.name],
    ["span", {id: "x"}, "x"]
  ]
];

and they end up with the same number of lines. But it's a matter of aesthetics, really.


The grouping operator just evaluates whatever expression is inside of it. You see this commonly with Immediately Invoked Function Expressions, where you need to turn what would normally be a function declaration into an expression, which can then be immediately invoked (hence, the name). However, a perhaps lesser known feature of the grouping operator is that it can also take a comma-delimited list of expressions, e.g.

function() {
  return (
    doSideEffects(),
    console.log("this is the second side effect"),
    1 + 1
  );
}

In this case it evaluates each of these expressions and returns only the last one (1 + 1).

tjb1982
  • 2,257
  • 2
  • 26
  • 39
  • 1
    As a good rule... always keep the return statement on one line in JavaScript. – scunliffe Aug 14 '13 at 01:52
  • To make matters worse, there are parsing differences between how Chrome/ Firefox interpret end-of-line and how IE interprets its. – Jon B Aug 14 '13 at 01:53
  • 5
    Related: [What are the rules for Javascript's automatic semicolon insertion (ASI)?](http://stackoverflow.com/questions/2846283/what-are-the-rules-for-javascripts-automatic-semicolon-insertion-asi) – bfavaretto Aug 14 '13 at 02:03
  • 1
    @JonB: There are? Could you provide some examples? –  Aug 14 '13 at 02:05
  • 3
    ASI should be abolished. It has no reason to exist except legacy code. `return \n (exp);` should work the same as `var foo = \n (exp);` – bryc Jul 21 '15 at 19:58
  • +1 if for no other reason than I finally found this after a zillion hits about inserting `\n` into a "returned string." Goodness, such a relief, thank you! – Maxim Paperno Aug 20 '23 at 14:58
1

Accepted Answer seems to be correct.

However I found this variant of a return line with line break at a function arg opening bracket DOES work:

myFunction(){
  return myOtherFucntion(
           myArg);
}

And this other variant with line break before '.' dot operator ALSO works:

myFunction(){
  return myObject
           .myObjectFunction();
}

(The style/readability of my examples are obviously a bit odd, but try to just pay attention to the conclusions they make, and exercise your own style as you find appropriate).

cellepo
  • 4,001
  • 2
  • 38
  • 57