You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
!function(){console.log('Welcome to the Internet. Please follow me.');}();
...But I have no particular preference on where parens should go for IIFEs that aren't also modules. Usually they're not very useful -- if it needs to be hidden, make it its own module -- but in the cases where they are it doesn't really matter to me. Both seem equally readable.
Is there enough of a difference to make this worth codifying?
Both work the same. It starts to get interesting when one of the modules is missing a trailing semicolon:
// problem(function(){console.log('module1');})()(function(){console.log('module2');})();// => module1// => TypeError: undefined is not a function// crockford problem(function(){console.log('module1');}())(function(){console.log('module2');}());// => module1// => module2// => TypeError: undefined is not a function
With a missing semicolon, each set of parens is trying to immediately-invoke the preceding expression. That would be the return value of the preceding IIFE.
(function(){returnundefined;})()();// => TypeError: undefined is not a function// equivalent(undefined)();(function(){returnundefined;}())();// crockford// => TypeError: undefined is not a function// equivalent(undefined());
So the difference is when the TypeError happens. Let's check out what the arguments are up to. Note that console.log() returns undefined:
// new module1.js(function(){console.log('module1');// return a function that logs it's// arguments when invokedreturnfunction(){console.log(arguments);};})()
// new production.js// unminified problem for readability(function(){console.log('module1');// return a function that logs it's// arguments when invokedreturnfunction(){console.log(arguments);};})()(function(){console.log('module2');})();// => module1// => [function() {// console.log('module2');// }]// => TypeError: undefined is not a function// the first step is to invoke the first module(function(){console.log('module1');returnfunction(){console.log(arguments)};})()// => module1// then it invokes the return value// with module2 as arguments(function(){console.log(arguments)})(function(){console.log('module2');});// => [function() {// console.log('module2');// }]// then it tries to invoke the return value.// console.log returns undefined so:(undefined)();// => TypeError: undefined is not a function
Now let's do that same example with the crockford way:
// new crockford module1.js(function(){console.log('module1');// return a function that logs it's// arguments when invokedreturnfunction(){console.log(arguments);};}())
// new production.js// unminified problem for readability(function(){console.log('module1');// return a function that logs it's// arguments when invokedreturnfunction(){console.log(arguments);};}())(function(){console.log('module2');}());// => module1// => module2// => [undefined]
There's no TypeError because of the returned function. The returned function that logs the arguments is then getting invoked with the return value of module2, which is undefined.
With that understanding, let's go back to the original example, where there was a TypeError:
// crockford problem(function(){console.log('module1');}())(function(){console.log('module2');}());// => module1// => module2// => TypeError: undefined is not a function// it invokes module1(function(){console.log('module1');}())// => module1//it invokes module2(function(){console.log('module2');}());// => module2// equivalent(undefined(undefined))// => TypeError: undefined is not a function
Conclusion
The (function{})(); and (function(){}()); IIFEs can act differently in the missing semicolon situation.
Use linter or a tool to make sure modules aren't missing trailing semicolons when working on modules.
To be extra safe add a leading semicolon to the IIFE:
Activity
reissbaker commentedon Nov 8, 2012
For modules we've decided on this:
...But I have no particular preference on where parens should go for IIFEs that aren't also modules. Usually they're not very useful -- if it needs to be hidden, make it its own module -- but in the cases where they are it doesn't really matter to me. Both seem equally readable.
Is there enough of a difference to make this worth codifying?
hshoff commentedon Nov 8, 2012
If you don't care about the return value of the IIFE, it could also be any of the following:
Let's explore this a bit more.
Both work the same. It starts to get interesting when one of the modules is missing a trailing semicolon:
With a missing semicolon, each set of parens is trying to immediately-invoke the preceding expression. That would be the return value of the preceding IIFE.
So the difference is when the TypeError happens. Let's check out what the arguments are up to. Note that
console.log()returnsundefined:Now let's do that same example with the crockford way:
But wait, there's no TypeError here...
There's no TypeError because of the returned function. The returned function that logs the arguments is then getting invoked with the return value of module2, which is
undefined.With that understanding, let's go back to the original example, where there was a TypeError:
Conclusion
The
(function{})();and(function(){}());IIFEs can act differently in the missing semicolon situation.Use linter or a tool to make sure modules aren't missing trailing semicolons when working on modules.
To be extra safe add a leading semicolon to the IIFE:
Hope that helps!
jcutrell commentedon Nov 8, 2012
A fantastically thorough explanation.
egonyuri commentedon Nov 16, 2012
Incredible explanation.
mikejoyceio commentedon Mar 22, 2015
Great explanation. Thanks.
jaan commentedon Mar 22, 2015
Good Explanation @hshoff
freeethy commentedon May 6, 2015
Great explanation @hshoff . Thanks.
[eslint config] [breaking] require outer IIFE wrapping; flesh out gui…
[eslint config] [breaking] require outer IIFE wrapping; flesh out gui…
xiehongyang commentedon Apr 21, 2016
Cool! help me a lot
[eslint config] [breaking] require outer IIFE wrapping; flesh out gui…
[eslint config] [breaking] require outer IIFE wrapping; flesh out gui…
[eslint config] [breaking] require outer IIFE wrapping; flesh out gui…
[eslint config] [breaking] require outer IIFE wrapping; flesh out gui…
[eslint config] [breaking] require outer IIFE wrapping; flesh out gui…
[eslint config] [breaking] require outer IIFE wrapping; flesh out gui…
[eslint config] [breaking] require outer IIFE wrapping; flesh out gui…
[eslint config] [breaking] require outer IIFE wrapping; flesh out gui…