hoist variable declarations to parameters in IIFEs that don't mention `arguments`
(function(something){
var a, b;
sideEffect(a(b));
})(somethingElse)
is a common pattern that can be shortened with a step that provides the following transformation:
(function(something, a, b){
sideEffect(a(b));
})(somethingElse)
You just have to watch out for arguments references within the function body (but not nested under other functions).
Good catch!
And we should check function expression is not named because this optimization has an effect on Function.length.
Sure, Function.length of user defined function isn't a part of ECMA262 5.1th spec, but it will be defined in ES6 spec, so we should take care about this.
I've committed initial pass implementation!
FYI, I dropped this for now from UglifyJS v2 because I determined that it's unsafe when a variable is used prior to being initialized; here's a simplified example:
function counter() {
var x;
return function() {
if (x == null) return x = 0;
return x = x + 1;
}
}
==>
function counter(x) {
return function() {
if (x == null) return x = 0;
return x = x + 1;
}
}
Calling it with no arguments, or with a null/undefined argument is fine, but my function did sometimes receive an extra-argument, which made the inner function think that x != null and returned a bogus value.
I plan to bring this back, but need to think it more carefully.
EDIT: so it's got nothing to do with access to arguments, in fact; that doesn't even matter. What matters is to check that the variable is not used before being assigned. If it is, then the transformation is likely buggy.
@mishoo: This can be done for functions where the variable is assigned before it is otherwise referenced (which seems to be what you're referring to), but this issue was regarding only IIFEs.