5

why this kind of bad design is made on js? Is there any special reason to design the automatic semicolon insertion like this?

Here is my code, It is not work in js in chrome:

(function(){console.log("abc");})()

(function(){console.log("123");})();

Here is the error:

Uncaught TypeError: (intermediate value)(...) is not a function

I know the right version of this code is :

(function(){console.log("abc");})();

(function(){console.log("123");})();

I just want to know why js syntax is designed so stupid. History reason?

I also add this question as a warning to everybody try to use the automatic semicolon insertion of javascript, please just add ; everywhere it needs, the automatic semicolon insertion of javascript is rubbish. It does not work as your expect.

The exist answer is too complex to my case, so I ask a new one:

https://stackoverflow.com/a/2846298/1586797

Another looks good but not work case 2:

x=1

(function(){console.log("123");})()
bronze man
  • 1,470
  • 2
  • 15
  • 28

7 Answers7

4

The linked question's answers explain the spec's three rules for ASI, for example this one. tl;dr:

  • If it doesn't work, try with semicolon.

  • The program should end with a semicolon.

  • If a statement says "can't put newline here", punish it with semicolon.

Your code does not satisfy any of the criteria.

  • The first line could return a function, and if so that function should be allowed to be invoked; so ( that the second line begins with is not illegal

  • The first line is not the last line of the program

  • There is no restricted syntax here.

Therefore, no automatic semicolon for you.

Some people have thus claimed that while (f(){})() syntax is good IIFE syntax, it might be good to do !f(){}() instead:

!function(){console.log("abc");}()

!function(){console.log("123");}();

This works as intended because ! just negates the (discarded) result of the function application, and also because ! as purely unary operator is an illegal character to continue the first line (i.e. f(){}()! is not a thing). This triggers rule 1, and ASI can take place.

The counterargument is that it is butt-ugly (i.e. for anyone not already familiar with the practice, it takes a while for them to understand the purpose of ! in this idiom).

Your second example is similar in nature: as far as the JS parser is concerned, 1 is a value (the fact that it is an integer and could not possibly be a function is a bit lost to it). Look at this example that syntactically is completely equivalent to yours:

a=function(f) { console.log("A CALLED!"); return f; }
x=a
(function(){console.log("123");})()
# => A CALLED!
     123

Here, a is a function, so it can be invoked with function(){console.log("123");} as an argument; it returns function(){console.log("123");} unchanged after printing to the console; then () invokes that return value, and 123 is printed as well. Everything works. Thus, Rule #1 is not triggered, no semicolon for you.

Amadan
  • 191,408
  • 23
  • 240
  • 301
  • Sorry, I can answer the question you posed in the title, by trying to elucidate the "answer too complex to my case". Why it is designed so, I would have to be telepath. But almost certainly history and backward compatibility - the default answer for almost all JS design issues. JS turned out to be a pretty neat language in the end, for something that was originally designed and implemented in _eight days_. – Amadan Aug 13 '18 at 07:16
  • This is a great explanation, thank you. I am reading a JS book called JavaScript - Functional Programming for JavaScript Developers it is a few years old. In the second chapter, it presents ```(function sayHello() {console.log("hello!");})();``` as a working code snippet. ASI really thew me, and you feel like a moron when you cannot get chapter 2 code to work. :) – dimButTries Dec 31 '20 at 12:04
2

Without the semicolon those statements are chained. You call the first function and give the second func as argument to the return value of the first one. This could actually work, if the first function had a function as return value.

When you expand the code it becomes more obvious:

var a = function(){console.log("abc");};
var b = function(){console.log("123");}
(a)()
(b)();

the last two lines become:

(a)()(b)();

this is equivalent to

var x = a();
x(b);

since a does not return anything, it cannot call it as function with b as argument.

dube
  • 4,898
  • 2
  • 23
  • 41
2
(function(){console.log("abc");})()

(function(){console.log("123");})();

is equivalent to:

(function(){console.log("abc");})()(function(){console.log("123");})();

And is what is usually referred to as function currying. For IIFEs (immediately invoked function expressions) you need to end with ;

For more on function currying see this post. Obviously your console log functions do not work as currying functions, but the syntax yourFunction(a)(b)(c) is a cool feature of the language that is used for currying.

Jensei
  • 450
  • 1
  • 4
  • 17
2

Your code can be simplified as:

(function(){})()()();

This code will get same error.

The () expect a expression to call.

The first () call the (function(){}), the second () call the (function(){})()'s result, but the result is not a function, so it's wrong.

Degas
  • 35
  • 8
1

I think this will be clearer if you use this:

x=1

(function(){console.log("123");})()

The error states 1 is not a function. Makes it clear that (function...) is treated like the argument of a function call to 1:

x=1(function(){console.log("123");})()
kabanus
  • 24,623
  • 6
  • 41
  • 74
1

Because ()() is self-invoking function and ();() are two differnt functions and interpreter is interpreting it accordingly.

Here two pieces of code are totally different for an interpreter.

(function(){console.log("abc");})()(function(){console.log("123");})();

and

(function(){console.log("abc");})();(function(){console.log("123");})();

however, this code will work fine

var a=12
var b=10
console.log(a+b)
Deepak
  • 1,510
  • 1
  • 14
  • 27
1

Long answer sort :

(function(){console.log("abc");})()

is trying to immediately-invoke the preceding expression which is

(function(){console.log("123");})();

Which would be the return value of the preceding IIFE.

IIFEs can act differently in the missing semicolon situation. That is why we see code as follows:

;(function() {
  console.log('abc');
})()

Please have a look of details description here : https://gist.github.com/khellang/8518964

Anupam Singh
  • 1,158
  • 13
  • 25
  • :) instead of using IIFE we can simply define function in call the function just after that. but IIFE is use to prevent accessing the outer variables and polluting global variables. https://developer.mozilla.org/en-US/docs/Glossary/IIFE – Anupam Singh Aug 13 '18 at 07:15