158

Why do the code snippets below, taken from this article, produce different results due to only a single change in the placement of curly braces?

When the opening curly brace { is on a new line, test() returns undefined, and "no - it broke: undefined" is displayed in the alert.

function test()
{
  return
  { /* <--- curly brace on new line */
    javascript: "fantastic"
  };
}

var r = test();
try {
  alert(r.javascript); // does this work...?
} catch (e) {
  alert('no - it broke: ' + typeof r);
}

When the brace is on the same line as return, test() returns an object, and "fantastic" is alerted.

function test()
{
  return { /* <---- curly brace on same line */
    javascript: "fantastic"
  };
}

var r = test();
try {
  alert(r.javascript); // does this work...?
} catch (e) {
  alert('no - it broke: ' + typeof r);
}
double-beep
  • 5,031
  • 17
  • 33
  • 41
JustLearn
  • 3,645
  • 10
  • 29
  • 30
  • 2
    the semi-insertion semantics after `return` are slightly different than in other places, and a line break "means more" in that spot than it would "midstream". – dandavis Jun 03 '15 at 21:43
  • In simple whatever you write next line of return will be ignored by javascript. – Kanish Nov 23 '22 at 00:04

6 Answers6

207

That's one of the pitfalls of JavaScript: automatic semicolon insertion. Lines that do not end with a semicolon, but could be the end of a statement, are automatically terminated, so your first example looks effectively like this:

function test()
{
  return; // <- notice the inserted semicolon
  { 
    javascript: "fantastic"
  };
}

See also Douglas Crockford's JS style guide, which mentions semicolon insertion.

In your second example you return an object (built by the curly braces) with the property javascript and its value of "fantastic", effectively the same as this:

function test() {
    var myObject = new Object();
    myObject.javascript = "fantastic";
    return myObject;
}
Edric
  • 24,639
  • 13
  • 81
  • 91
Residuum
  • 11,878
  • 7
  • 40
  • 70
  • Exactly right. Crockford has a googletalk video on youtube where he illustrates this very clearly. – Rich Sep 04 '10 at 09:17
  • 6
    Fun Fact: On some engines you can comment out the auto-inserted semicolons – Christopher Tarquini Sep 06 '10 at 03:55
  • 1
    @ChrisT: What? Which ones? Is this explored anywhere? – Sean McMillan Jun 06 '13 at 15:51
  • 1
    @SeanMcMillan I've definetly read articles about it but I can't seem to find any of them from a quick search. I remember that putting `return /*` and then `*/{ ` would effectively comment out the hidden semi-colon in older versions of chrome. Not sure if that still applies – Christopher Tarquini Jun 11 '13 at 00:07
  • 3
    Because of these quirks I made a promise to myself 10 years ago: stay away from the web! I prayed that the Interwebs would fade away... Unfortunately it didn't go as planned, and now I have to struggle with these issues as well. Karma is a b*tch :) – Jowen Apr 14 '14 at 11:19
  • Here's another example of an issue: ```BB.promisifyAll(myFs); // name the anon function (async myReadFileAsync => { const contents = await myFs.readFileAsync('filename.txt') console.log('promisifyAll: ', contents) })()``` Without the `;` it will try to execute the return from `BB.promisifyAll(myFs)` which is not what I intended. – Force Hero Nov 29 '17 at 11:16
  • 3
    I've seen people that are religiously against semicolons in JavaScript, I've always wondered what do they do with that extra time they save by not putting semicolons. – Iman Mohamadi Dec 13 '18 at 14:50
14

Javascript doesn't require semicolons at the end of statements, but the drawback is that it has to guess where the semicolons are. Most of the time this is not a problem, but sometimes it invents a semicolon where you didn't intend one.

If you format the code like this:

function getAnswer() {
   var answer = 42;
   return
      answer;
}

Then it is interpreted like this:

function getAnswer() {
  var answer = 42;
  return;
  answer;
}

The return statement takes its parameterless form, and the argument becomes a statement of its own.

The same happens to your code. The function is interpreted as:

function test()
{
  return;
  {
    javascript : "fantastic"
  };
}
ksav
  • 20,015
  • 6
  • 46
  • 66
Guffa
  • 687,336
  • 108
  • 737
  • 1,005
5

I personally prefer the Allman Style for readability (vs K&R style).

Instead of…

function test() {
  return {
    javascript : "fantastic"
  };
}

I like…

function test() 
{
  var obj =
  {
    javascript : "fantastic"
  };

  return obj;
}

But this is a work-around. I can live with it though.

Michael R
  • 1,547
  • 1
  • 19
  • 27
  • 6
    I think we should avoid personal preferences that deviate from the mainstream. We should follow the choices of the majority, which promotes consistency, which will increase readability – Jowen Apr 14 '14 at 11:12
  • 2
    I find his code more readable than the K&R. Pretty subjective when you mean "readable" – Bran Mar 23 '16 at 05:15
  • I prefer the Allman too... but due to ASI, when I need to return an object, I leave the semi on the same line as the return. I prefer this than to add one "var x= " line... – Mik Apr 01 '19 at 15:35
  • Allman style looks like bloat to me. sonarlint would flag this unnecesarry variable decrlation as code smell. – Ali Mert Çakar Feb 06 '23 at 19:21
2

It's because javascript most often puts ";" at the end of each line, so basicly when you have return { in same line, javascript engine see that there will be something more, and when its in new line it thinks you forgot to put ";", and puts it for you.

cichy
  • 10,464
  • 4
  • 26
  • 36
2

The curly braces here indicate the construction of a new object. Thus your code is equivalent to:

function test() {
  var a = { javascript : "fantastic" };
  return a;
}

which works whereas if you write:

function test() {
  var a = { javascript : "fantastic" };
  return; // ; is automatically inserted 
      a;
}

it no longer works.

Darin Dimitrov
  • 1,023,142
  • 271
  • 3,287
  • 2,928
1

The problem is indeed semicolon injection as described above. I just read a good blog posting on this subject. It explains this issue and a whole lot more about javascript. It also contains some good references. You can read it here

Ivo van der Wijk
  • 16,341
  • 4
  • 43
  • 57