-
Notifications
You must be signed in to change notification settings - Fork 26.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Defensive programming benefit of the bang method ("!") is not correct. #44
Comments
You would have to prepend a semicolon... If the
The !function(){console.log("ham");}() // Missing semicolon!
!function(){console.log("cheese");}(); As you can see, there's no I can't speak for file concatenation in Windows environments — all I can say is we don't use them for deployment at Airbnb, and so we don't worry about their behavior. My hunch is things work the same way over there too, though. |
UNIX The :; echo 0x61 | xxd -p -r > onea # Put a single ASCII 'a' in a file.
:; echo 0x62 | xxd -p -r > oneb # Put a single ASCII 'b' in a file.
:; echo 0x0a | xxd -p -r > onenl # Put a single ASCII newline in a file.
:; wc -c onea oneb onenl # Each file has only one byte.
1 onea
1 oneb
1 onenl
:; wc -l onea oneb onenl # Only the last file has a "line".
0 onea
0 oneb
1 onenl
:; cat onea oneb onenl # The 'a' and 'b' are joined on one line.
ab Many people see UNIX is all about flat text files, but really it's all about Maybe in this case, instead of inserting semicolons you could insert newlines. |
Thanks @reissbaker and @solidsnack, I learned something here. Both of you are right when I was trying to understand how the bang method was defensive I did simulate file concatenation manually. However, as you point out the protection is not derived from the method itself, rather its a function of the fact that it works when preceded with a newline, which happens to be how *NIX environments handle things. I think I might make a blog post about this, because I think there are others under the same misconception as myself. Thanks again for sharing your JS knowledge. |
Thanks for the discussion, this was a good read! 🍻 |
Wow, only recently got linked back to this thread. @solidsnack, thank you, that was enlightening! One more note on !-modules:
Unfortunately, a newline isn't sufficient to prevent later (non-!-style) modules from throwing errors. For example, run the following in a Javascript console: !function() {}()
(function() {}()); Despite the presence of a newline following the !-module, the above code will throw a However, a !-module with a terminating semicolon is safe regardless of the safety of what precedes or follows it, as running the following example should illustrate: (function() {}())
!function() {}();
(function() {}()) I suppose the reason !-modules generally are safe is because most text editors terminate files with the LF character (Windows editors use both a CR and an LF, but the existence of the LF is sufficient). I'd imagine this is a relatively safe thing to rely on, especially in an all-*nix environment — for an example of another tool that expects this behavior, GCC will issue warnings when trying to compile files that don't end with a newline. TL;DR: Using !-modules with a terminating semicolon will prevent accidental errors that arise due to concatenation using the |
This discussion is quite old, but I have to ask... Why would ";" be silly? It seems like a more logical option. A "!" actually seems very illogical. Is there a reason other than personal preference? |
Unfortunately, a |
(I'm assuming you mean the following: ;function(){
// module
}(); vs. our current recommendation: !function(){
// module
}(); Unfortunately, the semicolon-prefixed function will cause the invocation to throw an error.) |
Aaah. I get it now. Thanks. |
I am surprised there is no mention of: This seems to be the safest of all and removing leading ';' won't break it. |
For javascript < ES6 I am personally a fan of using void instead of ! (bang), because I find the bang distorts the intention whereas void seems much more appropriate: // module 1
void function module1(context){
// module 1 code...
// local variables are declared like
var localModuleVariable = 'some local variable'
// export to parent context
context.module1 = 'module 1 loaded';
}(this);
// module 2
void function module2(context){
// module 2 code...
context.module2 = 'module 2 loaded';
}(this);
// anonymous iife
void function(){
// anonymous iife code...
}(); But in ES6 we get block scoping with let variables so you could do: // module 1
{
// module 1 code...
// local variables are now declared with let to be scope-able
let localModuleVariable = 'some local variable';
// export to parent context
var module1 = 'module 1 loaded';
}
// module 2
{
// module 2 code...
var module2 = 'module 2 loaded'
}
// anonymous iife
{
// anonymous iife code...
} |
@iod you still would have to prefix void with a semicolon if you want to prevent errors with sloppy code on concatenation. Nevertheless, I like the idea with void very much. |
or a comment would be fine @p3k, which you might have when using eslint: /* global define */
void function () {
}(...) |
First off this is a great document, and thanks for sharing it. I have read the entire file end-to-end as I work on my own personal style guide. However, I was looking at your module example and you assert that "!" protects you from concatenation errors. However, I don't think this is correct. Consider the following example:
Maybe I am misunderstanding how you expected things to work.
I think you still need to prepend a semicolon to truly protect yourself from concatenation errors.
The text was updated successfully, but these errors were encountered: