Execute function with semicolon in JavaScript - javascript

I have two functions:
const functionA = function() {
return 30;
}
const functionB = function(num) {
return num*2;
}
const c = functionB(functionA());
I know it is very straightforward the way it is, but why can't we write the code like this:
const c = functionB(functionA();); // with an semicolon in the inner braces
Doesn't that inner functionA get executed too?
I have another function:
const functionAnother = function() {
//does nothing
}
We know that it is illegal to have an empty line of execution just like:
;
but we can write code like:
functionAnother();
and since functionAnother returns nothing, isn't it just like this:
;

The semicolon doesn't have anything to do with execution, it just marks the end of the statement. Parens () are really the thing that invoke the execution.
so, const c = functionB(functionA();); throws an error because JS thinks you're starting a new line with nothing but ); on it after the first semicolon (and the statement on the line before it is incomplete/invalid syntax).
However, if you remove that semicolon...
const c = functionB(functionA());
...you have something perfectly valid (and common). This will execute functionA first, and pass its return value as a parameter to functionB.
Does this help your understanding?

When you pass the result of functionA() into functionB, you are treating the result of functionA() as an expression. Because it is an expression (something that has a value, in this case, 30) and not a statement (an instruction to do something), you would not put a semicolon after it. Does that make sense?
I'm not certain what your second question is asking. If you're trying to have an empty line of code, you can make one by not writing anything on that line. I believe that ; is actually a legal JavaScript statement, going by this page: https://docstore.mik.ua/orelly/webprog/jscript/ch06_19.htm

To answer your first question:
Semicolons are used at the end of statements. A statement can be thought of as an action or instruction which will be performed/carried out by the program. The semi-colon marks the end of this instruction. Thus, when you use a semi-colon in the middle of a statement (ie when it isn't finished) your technically ending your instruction early, and thus you'll get a syntax error:
function functionA() {};
function functionB() {};
const c = functionB(functionA(););
To answer your second question:
When a function doesn't return anything it is actually implicitly returning undefined:
function functionA() {
}
console.log(functionA());
And so instead of having:
;
By itself, you have something like so:
console.log("foo");
undefined;
console.log("bar");

Related

Immediately invoked function expression without using grouping operator

I'm trying to immediately invoke a function without using IIFE pattern (enclosing a function definition inside parentheses). Here I see two scenarios:
When a function declaration is invoked immediately: gives SyntaxError.
When a function expression is invoked immediately: executes successfully.
Example 1: gives SyntaxError
//gives `SyntaxError`
function() {
console.log('Inside the function');
}();
Example 2: Executes without any error
// Executes without any error
var x = function() {console.log('Inside the function')}(); // Inside the function
So, I have these doubts:
With this approach, why does it give an error for function declaration but not for function expression?
Is there a way we can immediately invoke a function declaration without using IIFE pattern?
In your code you don't have name for the function that's the reason for syntax error. Even if you would had name it would have thrown error.
function func(){
console.log('x')
}();
The reason is the function declaration doesn't return the values of the function however when you wrap function declaration inside () it forces it be a function expression which returns a value.
In the second example the function() {console.log('Inside the function')} is considered expression because it's on RightHandSide. So it executes without an error.
Is there a way we can immediately invoke a function declaration without using IIFE pattern
You can use + which will make function declaration an expression.
+function(){
console.log('done')
}()
If you don't want to use + and () you can use new keyword
new function(){
console.log('done')
}
Extra
A very interesting question is asked by #cat in the comments. I try to answer it.There are three cases
+function(){} //returns NaN
(+function(){return 5})() //VM140:1 Uncaught TypeError: (+(intermediate value)) is not a function
+function(){return 5}() //5
+function(){} returns NaN
+ acts as Unary Plus here which parses the value next to it to number. As Number(function(){}) returns NaN so it also returns NaN
(+function(){return 5;})() returns Error
Usually IIFE are created using (). () are used to make a function declaration an expression + is short way for that. Now +function(){} is already an expression which returns NaN. So calling NaN will return error. The code is same as
Number(function(){})()
+function(){return 5;}() returns 5
In the above line + is used to make a statement an expression. In the above example first function is called then + is used on it to convert it to number. So the above line is same as
Number(function(){return 5}())
In the proof of statement "+ runs on after the function is called" Consider the below snippet
console.log(typeof +function(){return '5'}());
So in the above snippet you can see the returned value is string '5' but is converted to number because of +
A function declaration, like
function foo() {
}
defines (and hoists) the variable name foo as a function in the current scope. A function declaration doesn't evaluate to a value; it just does something, a bit like an if does something (rather than evaluate to a value).
You can only invoke values which are functions, eg
<somevalue>()
where somevalue is a variable name that refers to a function.
Note that function declarations require function names, because otherwise there's no variable name to assign the function to - your original
//gives `SyntaxError`
function() {
console.log('Inside the function');
}();
throws not because of the () at the end, but because of the lack of a name.
You can put parentheses at the end of a function declaration, as long as there's something inside the parentheses - but these parentheses do not call the function, they evaluate to a value:
function x() {
console.log('Inside the function');
}(console.log('some expression inside parentheses'));
The interpreter sees these as two separate statements, like
function x() {
console.log('Inside the function');
}
// completely separate:
(console.log('some expression inside parentheses'));
The inside of the parentheses gets evaluated and then discarded, since it doesn't get assigned to anything.
(Empty parentheses are forbidden because they can't be evaluated to a value, similar to how const foo = () is forbidden)
The E in IIFE stands for expression, and without the wrapping parenthesis your function is not evaluated as an expression thus the syntax error.
creating an expression is a way of tricking the interpreter and be able to invoke the function immediatly
(function() {
console.log('Inside the function');
})();
In your example you have a function statement followed by the grouping operator, but it's syntactically incorrect for two reasons, first it doesn't have a name, and second because the grouping operator must have an expression inside it, infact if you add a valid one the error will disappear, still you won't obtain your desired result.
function foo() {
console.log('Inside the function');
}();
function foo() {
console.log('Inside the function');
}(1+2);
In order to invoke something, it has to be a function value, a declaration just declares a name, and does not evaluate to the function value itself, hence you cannot invoke it.
A declaration cannot be invoked for the above reason. You have to end up with an expression somehow, either through assignment or grouping (IIFE). So that is a no.
If you give us more context on why you would want to do that, maybe we can help with suggestions.
Not sure why you would want to do it, but:
Is there a way we can immediately invoke a function declaration without using IIFE pattern?
Well, if for function declaration you mean using the keyword function as in:
function name() { return this.name; }
As far as I know, no. You need the extra parentheses to tell the runtime not to assign the function to a name variable, if I understand this stuff right.
Now, what you actually can do is to use Function as in:
new Function('console.log("ey there")')();
Which will execute the console.log code. No need for IIFE here. But I don't see how this could be better than an IIFE.
you can call in either below ways -
~function(){console.log("hi")}()
!function(){console.log("hi")}()
+function(){console.log("hi")}()
-function(){console.log("hi")}()
(function(){console.log("hi")}());
var i = function(){console.log("hi")}();
true && function(){ console.log("hi") }();
0, function(){ console.log("hi") }();
new function(){ console.log("hi") }
new function(){ console.log("hi") }()

Function is working when assigned to a variable but throwing SyntaxError when executed by itself

I had an IIFE like this one:
(function a() {
return "b";
}());
Executed in the console, it returns "b".
I removed the first set of parentheses, thinking that this'll make the "a" function global, but still work, and return "b":
function a() {
return "b";
}();
But it throws a SyntaxError:
Uncaught SyntaxError: Unexpected token )
Then, I tried converting the function to an expression by assigning to a variable, and it worked:
var c = function a() {
return "b";
}();
console.log(c); // prints b
Why does this happen? Why is it working as an expression but not by itself?
The second piece of code is not what it looks like.
This code looks like a function that is being immediately executed:
function a() {
return "b";
}()
But in reality, it's just a function declaration followed by an empty expression, which is not allowed:
function a() {
return "b";
}
() // not allowed - empty expression
Ben Alman explains this in his article on IIFE's:
When the parser encounters the function keyword in the global scope or
inside a function, it treats it as a function declaration (statement),
and not as a function expression, by default.
...
While parens placed after an expression indicate that the expression
is a function to be invoked, parens placed after a statement are
totally separate from the preceding statment, and are simply a
grouping operator (used as a means to control precedence of
evaluation).
The grouping operator needs to contain an expression to evaluate. By itself it's of no meaning:
() // meaningless
2 + 3 * 4 // 15
(2 + 3) * 4 // 20
In IIFE's, the outer parentheses are just a means of forcing the parser to expect an expression.
This is why the expression var c = function() { return "b"; }(); also works; it's because the parser knows to expect an expression because of the assignment to c.
Side Note
Alman also recommends against using self-invoking functions without using the outer parentheses when assigning to variables(i.e. var v = function(){...}()) because it's bad practice:
In cases where the extra “disambiguation” parens surrounding the
function expression are unnecessary (because the parser already
expects an expression), it’s still a good idea to use them when making
an assignment, as a matter of convention.
Such parens typically indicate that the function expression will be
immediately invoked, and the variable will contain the result of the
function, not the function itself. This can save someone reading your
code the trouble of having to scroll down to the bottom of what might
be a very long function expression to see if it has been invoked or
not.

Syntax error on anonymous function declaration, but not after valid statement

I just spend long time digging through callbacks in promises wondering why some callbacks are not called. In the end problem was with incorrect declaration, instead of
Promise.when(null).then(function () {
var p = new Promise();
p.fail(new Error("some message"));
return p;
}).then(function () {
console.log("success");
}, function (err) {
console.log("failure");
});
I did
Promise.when(null).then(function () {
var p = new Promise();
p.fail(new Error("some message"));
return p;
}).then(function () {
console.log("success");
}), function (err) {
console.log("failure");
};
Regardless of Promise implementation details it boils down to one thing:
function(){};//throws SyntaxError
"something valid, or function call", function(){};//no error
I would like someone to explain this to me. Why first is throwing SyntaxError while latter is valid (at least in browser console)? It seems to declare anonymous function.
Same thing happens when I try
eval("function(){};//throws SyntaxError")
eval("'lala',function(){};//no error")
So can someone explain me why first is not valid while latter is ?
A statement that begins with the keyword "function" must be a valid function declaration statement. That requires a name for the function.
In an expression (or expression statement), that rule is different; no name is necessary because the function acts as a value in that context. No name is required then.
Thus this:
function myFunction() {
// ...
}
is a function declaration statement. This:
5 + function() {};
is an expression statement (a silly one, but JavaScript is ok with that). Similarly, your example that results in no error is an expression with the comma operator:
"lala", function() {};
The keyword "function" does not appear at the beginning of either of those two expressions, so the parser does not insist on a name for the function.
Your original code was not working because, as you figured out, the second function was not passed as a parameter - you put the closing paren before the function. It was causing no error because JavaScript recognized it as a function expression. Your use of the comma operator told JavaScript to expect the next statement to be an expression.
A function declaration cannot be anonymous, but a function expression can. A stand alone anonymous function looks like a function declaration that is missing an identifier to JavaScript. But, combined with an operator, JavaScript treats an anonymous function as the operator's operand expression.
The statement 'lala',function(){} consists of an expression ('lala') followed by an operator (,) followed by a function expression. This statement is similar: 0,function(){}. Promise.when(...).then(...) is also a valid expression, so Promise.when(...).then(...),function(){} works just the same.

Detail of operation of !function() { return false; } ()

!function() { return false; } ()
I'm aware why you might write something like this, but I have a question about the way it works. As I understand it, the exclamation mark does two things:
It acts on function() { return false; }, changing it into an expression
It also acts on the result of the executed function, so that the whole line evaluates to true
So my questions are:
Is this the correct explanation?
If it is correct, then since () binds more tightly than !, how did the first part (the change of the function itself into an expression) happen? Why doesn't the exclamation mark act on the whole line throughout?
according to operator precedence, the function declaration (which is shorthand for new Function) would happen first, the function call () would happen second, and the negation ! would happen last.
edit for clarity: You could rewrite that one line as this to accomplish the same thing:
// declare an anonymous function and assign it to the myFunc variable
var myFunc = function () {
return false;
};
// execute the function and store it's return value (false) in returnValue
var returnValue = myFunc();
// negate the return value (true)
var output = !returnValue;
1) It doesnt "change" it. It makes so when the parser goes through the "function" bit it goes expecting an expression, so the "function" is parsed as part of an (possibly anonymous) function expression instead of as a function statement.
2) It is acting on the whole line. If you look at the precedences, as suggested by jbabey, you see that function call binds more tightly then the negation operator so the whole like is evaluated as
! ((function(){})());
Or in a similar, perhaps more readable version:
var f = function(){ ... };
! (f());

TypeError with two consecutive self-executing anonymous functions

This question is inspired from the accepted answer here. Why does the following piece of code alert "first", then "second", then errors out with a TypeError?
(function() {
alert('first');
}())
(function() {
alert('second');
}())
The given explanation is that the returned value of the first function is trying to get called. But why did that happen? [Also, why didn't semi-colon insertion add a semi-colon after the first self-execution?]
Without semicolons it will evaluate to:
(function() {
alert('first');
}())(function() {
alert('second');
}())
The first function is executed, and since it does not return anything, it evaluates further to:
undefined(function() {
alert('second');
}())
Then the second function is executed, and it returns again undefined, so:
undefined(undefined)
Which does not work of course (TypeError since undefined is not a function). Separate function calls should be separated with a semicolon, as every statement should actually be.
ASI, Automatic Semicolon Insertion. Your code should've been written like this:
(function() {
alert('first');
}()); //<--semicolon
(function() {
alert('second');
}()); //<--semicolon
Instead, here's the step that are taken:
(function() {
alert('first');
}())
(function() {
alert('second');
}())
//now, the interpreter guesses that you mean to concatenate the two
(function() {
alert('first');
}())(function() {
alert('second');
}());
//it also inserts a semi-colon where it should've appeared at the end of the script
//first function doesn't return anything === returns undefined
undefined(function() {
alert('second');
}());
//second function doesn't return anything === returns undefined
undefined(undefined);
//however, the braces stay, since they can also mean function execution
undefined is not a function, therefore it cannot be executed, therefore, you get a TypeError.
It happened because that's the way your program was parsed. We could sumarise the program as
(some stuff) (some more stuff)
And it's clear that this should try to call the some stuff as a function. Of course a semi-colon would fix the problem and you were hoping that semi-colon insertion would have done it automatically for you. Without knowing the detailed insertion rules, I would just say that nothing was inserted becuse the rules are specifically designed to not change otherwise well defined behaviour.
Of course, you might not consider this behaviour "well defined". But language rules never work well in every situation.

Categories

Resources