Immediately invoked function expression without using grouping operator
Asked Answered
U

7

26

I'm trying to immediately invoke a function without using IIFE pattern (enclosing a function definition inside parentheses). Here I see two scenarios:

  1. When a function declaration is invoked immediately: gives SyntaxError.

  2. 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?
Uzbek answered 13/5, 2019 at 8:28 Comment(12)
Quick question. IIFE invokes code immediately and creates a scope. So what do you expect with immediately invoke a function declaration without using IIFE patternBlend
The main question here is, does JavaScript provides any ways for us to immediately invoke a function declaration without wrapping them inside parentheses?Uzbek
No you cannot. Anything which is written inside parentheses will be evaluated in javascript. So if you write function inside parens, then it will evaluate aka invoke the function. You can just write (4) on javascript console and it will give you 4 as output. By writing 4 in parens you are just evaluating a literal and hence it gives 4 back.Legnica
I see people here are calling the 2nd example as IIFE. So, do we really call it an IIFE, if it doesn't use the IIFE Pattern?Uzbek
+function(){console.log('done')}() and new function(){console.log('done')}() seem to work. I wonder, what's going under the hood here.Uzbek
"does JavaScript provides any ways for us to immediately invoke a function declaration without wrapping them inside parentheses?" - Yes - it only needs to disambiguate that it is function expression and not a function declaration, which can be done by e.g. prefixing with any operators (e.g. !function() { .... }). "why does it give an error for function declaration but not for function expression?" Have you noticed what IIFE means? "Immediately invoked function expression." It is not IIFD/E. Function invocation is an expression - and you cannot use a statement inside an expression.Atilt
@AadityaSharma what is an "IIFE pattern"? IIFE means an immediately invoked function expression. If you have a function expression and invoke it immediately, that's an IIFE. Your second example is exactly that - a function expression which you invoke. Same with +function(){} although it's more hacky - it merely forces this to be evaluates as an expression instead of declaration.Acetophenetidin
@all-the-downvoters - It'd be helpful if you can explain the reason(s), for the benefit of others.Uzbek
see: developer.mozilla.org/en-US/docs/Glossary/IIFEWattle
See plus sign in front of function name or What does the exclamation mark do before the function?Integrand
I see @Integrand has updated the title. Doesn't the new title alter the meaning of the original question being asked? Earlier it was Immediately invoke a function declaration without using IIFE pattern. As per MDN, IIFE is a design pattern. See - developer.mozilla.org/en-US/docs/Glossary/IIFEUzbek
@AadityaSharma The original title didn't make sense. It's impossible to immediately invoke function declarations, and its impossible to immediately invoke a function expression without it being an IIFE. The body of the question is more clear, and the answers are fine. So adjusting the title was the best I could do without voting to close (as either unclear, or duplicate on function declaration vs expression).Integrand
S
17

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 +

Shandy answered 13/5, 2019 at 8:39 Comment(5)
...but note that using new like that will have the side effect of constructing an object using the provided function as its constructor (and then immediately garbage collecting it, since you don't save the returned value). Try e.g. let foo = new function() { console.log("in function") }; console.log(foo); console.log(foo.constructor); to see what I mean.Scorn
Can you say why or how +function(){} is (correctly) NaN, and (+function(){ return 5 })() is (+ (intermediate value)) is not a function, yet +function(){ return 5 }() is 5?Samurai
@Samurai Your question worth to be answered in original answers rather than comments. I have added a detailed answer. Check it out. If any confusion ask meShandy
@MaheerAli this was helpful - In the second example the function() {console.log('Inside the function')} is considered expression because it's on RightHandSide.Uzbek
@AadityaSharma Yes absolutely.Shandy
U
14

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)

Unaffected answered 13/5, 2019 at 8:34 Comment(10)
Might help to have the last example without () to show it throws.Lather
It gives an error with a named function too function kaka() {console.log('Inside the function');}();Uzbek
@Unaffected - This example just executed whats there inside the last set of paratheses, ignoring the function declaration. (console.log('some expression inside parentheses'));Uzbek
Your answer lacks ,any alternative to invoke function immediately except iife.Ferdelance
@AadityaSharma The function declaration is not ignored - the variable name x gets assigned (and hoisted) to that function in the current scope. But x is never called, so you don't see Inside the function.Unaffected
@Shubh Yes, that's because function declarations cannot be immediately invoked - they do something, rather than evaluate to a value. They're not expressions. You'd have to use a function expression instead, to call it immediately.Unaffected
@Unaffected - but exactly I'm looking for is: x to get called without enclosing it inside parentheses.Uzbek
If x is a function declaration, you can't call it immediately, see above comment and first part of answer - either make it a function expression instead, or write x()Unaffected
@Unaffected This statement doesn't really seem to be right throws error not because of the () at the end, but because of the lack of a name. It gives an error with a named function too function kaka() {console.log('Inside the function');}();Uzbek
@AadityaSharma Yes, once you give it a name, it throws on the () at the end - as the last part of the answer describes, (Empty parentheses are forbidden because they can't be evaluated to a value, similar to how const foo = () is forbidden). Before you give it a name, it doesn't throw at the (), because the parser threw before, when the nameless function declaration was encounteredUnaffected
C
2

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);
Crucify answered 13/5, 2019 at 8:42 Comment(0)
F
1

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.

Fluviatile answered 13/5, 2019 at 8:36 Comment(0)
R
1

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.

Rabble answered 13/5, 2019 at 8:59 Comment(0)
S
1

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") }()
Supinator answered 23/5, 2019 at 16:27 Comment(0)
A
0

void operator can be used:

void function() {
  console.log('done')
}()
Acadia answered 19/9, 2023 at 18:29 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.