Comments (8)
If you don't care about the return value of the IIFE, it could also be any of the following:
!function(){}(); // => true
~function(){}(); // => -1
+function(){}(); // => NaN
-function(){}(); // => NaN
Let's explore this a bit more.
// module1.js
(function() {
console.log('module1');
})();
// module2.js
(function() {
console.log('module2');
})();
// production.min.js
(function(){console.log('module1');})();(function(){console.log('module2');})();
// => module1
// => module2
// crockford production.min.js
(function(){console.log('module1');}());(function(){console.log('module2');}());
// => module1
// => module2
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(){ return undefined; })()();
// => TypeError: undefined is not a function
// equivalent
(undefined)();
(function(){ return undefined; }())(); // 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 invoked
return function(){
console.log(arguments);
};
})()
// new production.js
// unminified problem for readability
(function() {
console.log('module1');
// return a function that logs it's
// arguments when invoked
return function(){
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');return function(){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 invoked
return function(){
console.log(arguments);
};
}())
// new production.js
// unminified problem for readability
(function(){
console.log('module1');
// return a function that logs it's
// arguments when invoked
return function(){
console.log(arguments);
};
}())(function(){
console.log('module2');
}());
// => module1
// => module2
// => [undefined]
But wait, there's no TypeError here...
// it invokes module1
(function(){ console.log('module1'); return function(){ console.log(arguments); };}())
// => module1
//it invokes module2
(function(){ console.log('module2'); }());
// => module2
// equivalent
(function(){ console.log(arguments); })(undefined)
// => [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:
// module1.js
;(function() {
console.log('module1');
})()
// crockford module1.js
;(function(){
console.log('module1');
}())
// module2.js
;(function() {
console.log('module2');
})();
// crockford module2.js
;(function() {
console.log('module2');
}());
// production.min.js
;(function(){ console.log('module1'); })();(function(){ console.log('module2'); })();
// => module1
// => module2
// crockford production.min.js
;(function(){ console.log('module1'); }());(function(){ console.log('module2'); }());
// => module1
// => module2
Hope that helps!
from javascript.
For modules we've decided on this:
!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?
from javascript.
A fantastically thorough explanation.
from javascript.
Incredible explanation.
from javascript.
Great explanation. Thanks.
from javascript.
Good Explanation @hshoff
from javascript.
Great explanation @hshoff . Thanks.
from javascript.
Cool! help me a lot
from javascript.
Related Issues (20)
- [spam]
- [spam]
- Support Biome extends HOT 3
- [spam] HOT 1
- [spam]
- [spam] HOT 1
- Multiline comments HOT 3
- [spam]
- [spam]
- TypeError: Failed to load plugin 'jsx-a11y' declared HOT 4
- [spam]
- [spam] HOT 1
- Regarding Updation HOT 4
- [spam] HOT 1
- [spam]
- Link 404 not found HOT 2
- Can we add on quiz sections on this repo too HOT 11
- [spam]
- eslint v9 support
- [spam]
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from javascript.