Why won't function foo(){}() run as an IIFE?
By FrontendPro Editorial Team Updated 9/26/2026
Answer
Because the parser reads it as two separate things, not one.
When function is the first token of a statement, JavaScript commits to parsing a function declaration. A declaration is a statement, and you cannot call a statement. So function foo(){}(); is read as a declaration of foo, followed by an empty pair of parentheses — which is a syntax error, since () on its own means nothing.
The fix: make it an expression
Anything that forces the parser into expression position works. Wrapping in parentheses is the conventional way:
(function foo() {
console.log("runs");
})(); // parentheses around the function
(function foo() {
console.log("runs");
}()); // parentheses around the whole call — equally valid
A leading operator does the same job more tersely, though it is harder to read:
!function () { console.log("runs"); }();
void function () { console.log("runs"); }();
And an arrow function needs no trick, because it is always an expression:
(() => console.log("runs"))();
Why IIFEs existed
Before block scoping and modules, a function was the only way to create a private scope. An IIFE kept helper variables out of the global namespace and gave you a place for private state — the module pattern was built on exactly this.
Most of that need is gone. let/const give you block scope with a bare { }, and every ES module already has its own scope, so top-level variables never leak. IIFEs still appear in three places: bundled output, code that must run immediately inside a non-module script, and as (async () => { ... })() to use await where top-level await is unavailable.
One practical note: always end the preceding statement with a semicolon. A line starting with ( will otherwise be treated as a call on whatever came before.
