esmangle icon indicating copy to clipboard operation
esmangle copied to clipboard

hoist variable declarations to parameters in IIFEs that don't mention `arguments`

Open michaelficarra opened this issue 13 years ago • 4 comments

(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).

michaelficarra avatar Sep 14 '12 21:09 michaelficarra

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.

Constellation avatar Sep 14 '12 21:09 Constellation

I've committed initial pass implementation!

Constellation avatar Sep 15 '12 16:09 Constellation

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 avatar Sep 17 '12 20:09 mishoo

@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.

michaelficarra avatar Sep 17 '12 20:09 michaelficarra