问题
To which extent does it make sense to pass plenty of global values to an IIFE?
The common thing is just to pass 3 as far as I see everywhere (window, document and undefined). But... would it make sense to pass more if they are used more than 10 times in the code just for the fact of minification?
In my case I found the global variable Math
14 times in the code. It would make sense to pass it to an IIFE in order to save 42 bytes. Which in this case is not a lot, but if we sum bit by bit different global variables, then it would always make sense to pass as many global variables as possible, right? (Symbol, Object, Error, Date, JSON...)
(function($, window, document, Math, undefined) {
$.fn.mydemo = function() {
};
}(jQuery, window, document, Math));
Then, why isn't this a common approach?
Update:
To explain the 42 bytes of reduction:
- Math = 4 characteres
- 1 character = 1 byte
- 14 times Math = 56 bytes
- Math will get replaced by a single character after minification
- As the function can be defined as function($, w, d, m, u)
- 14 characters of the shorten word Math (m) = 14 bytes
- 56 - 14 = 42 bytes of reduction
回答1:
would it make sense to pass more if they are used more than 10 times in the code just for the fact of minification?
If you care that much about minification, sure, why not?
The common thing is just to pass 3 as far as I see everywhere (
window
,document
andundefined
)
Yes, altough you see not passing document
, or passing jQuery
(aliased as $
), just as often. And of course it's not only about minification, but about performance, and you only care for window
and document
on that behalf.
it would always make sense to pass as many global variables as possible, right?
Well, except you don't use them in your code. Symbol
, Object
, Error
, Date
, JSON
, Math
and the others are not needed that often in most code. And developers don't like to do those byte counts you are suggesting every time they change a bit of code, so this IEFE boilerplate just stays as it is (and imho there's much cargo cult to it).
You would let your minifier do this automatically if you'd really care.
回答2:
First of all, those values are not IIFEs.
And this is not about “saving characters” by having shorter variables names inside the function (at least not mainly), but rather about variable lookup and the “cost” associated with it.
If you were to use f.e. document
inside your function without passing it in, then first a variable named document
would be searched in the scope of the function, and only when that fails, search would continue in the scope above that, and so on.
That is the reason for passing such objects as parameters into the function – so that a direct reference to them within the function scope exists, and they do not have to be looked up in higher outside scopes.
Sometimes, you might even see this used in such a form like this:
(function(document) {
// do something with document, such as:
document.foo();
document.bar = "baz";
})(document);
– in that form, it should be even more clear that this is not about saving characters in variable names. The object is still referred to as document
inside the function (which makes it clear what it is supposed to represent – the global document
object), and the only effect achieved by this is said shorter lookup.
回答3:
There are a number of cases where it makes sense to pass variables to an IIFE.
Aliasing
Passing a variable to an IIFE allows you to rename the variable within the function. This is commonly seen when using jQuery, particularly when noConflict
is used:
(function ($) {
//in here $ will be the same as jQuery
}(jQuery));
Aliasing also helps minifiers to minify code, when you see something like:
(function (document, slice, Math) {
...
}(document, Array.prototype.slice, Math));
The minifier can rename the parameters to whatever it wants, and save you bytes. For large scripts using these properties a lot, it can be significant savings when it gets turned into:
(function(a,b,c){...}(document,Array.prototype.slice,Math));
Portability
This is more of an edge case than a general rule, but it's common to see a global IIF in the form of:
(function (global /* or window */) {
...
}(this));
This allows for portability between node.js and the browser so that the global variable has the same name in both environments.
Character Savings
While I already mentioned that minifiers can reduce the character count by changing the names of aliases, you may want to do this manually if you're participating in a code golf challenge.
Reference Safety
If you're authoring a script that must work in whatever environment its dumped into (think google analytics), you'll want to be sure that the global methods you're calling are what you expect. Storing a reference to those functions by passing them as parameters is one way to preserve the reference to the functions from becoming overridden by a malicious or ignorant programmer.
To answer the question in your title:
How many globals make sense to be passed to the IIFE wrapper?
As many as you need and no more. If you need to alias one or two variables, pass one or two references. If you need to be sure that the global functions aren't being changed, you may end up with 100 parameters. There's no hard-and-fast rule on this.
来源:https://stackoverflow.com/questions/28615068/how-many-globals-make-sense-to-be-passed-to-the-iife-wrapper