Why do results vary based on curly brace placement?
Asked Answered
E

6

159

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);
}
Estrin answered 4/9, 2010 at 8:47 Comment(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".Doorstop
In simple whatever you write next line of return will be ignored by javascript.Aufmann
C
208

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;
}
Catalonia answered 4/9, 2010 at 8:50 Comment(7)
Exactly right. Crockford has a googletalk video on youtube where he illustrates this very clearly.Dasyure
Fun Fact: On some engines you can comment out the auto-inserted semicolonsMoulden
@ChrisT: What? Which ones? Is this explored anywhere?Eisteddfod
@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 appliesMoulden
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 :)Guardhouse
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.Laspisa
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.Driggers
M
15

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"
  };
}
Maccabean answered 4/9, 2010 at 9:0 Comment(0)
H
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.

Heady answered 23/2, 2012 at 20:11 Comment(4)
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 readabilityGuardhouse
I find his code more readable than the K&R. Pretty subjective when you mean "readable"Obturate
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...Orchestra
Allman style looks like bloat to me. sonarlint would flag this unnecesarry variable decrlation as code smell.Link
M
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.

Mockheroic answered 4/9, 2010 at 8:50 Comment(1)
I don't get why cichy's, Darin's and Ivo's answers were downvoted?Schlesinger
K
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.

Kessler answered 4/9, 2010 at 8:52 Comment(0)
D
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

Domineer answered 4/9, 2010 at 8:52 Comment(1)
Yes, i also read that, ater reading i asks here to explain better by mastermind of js.Estrin

© 2022 - 2024 — McMap. All rights reserved.