1

Premise: function literals are bound to their names (unless used anonymously) only when the respective assignment is executed. For example, one can do conditional definition like this:

var fn;
if (some condition) {
    fn = function() {
        // some code
    };
} else {
    fn = function() {
        // some different code
    };
}

Inner functions, on the other hand, behave as if they were always bound to their names, inside the respective scope, disregarding any code path considerations:

function outer() {
    inner();
    return;

    function inner() {
        // some code
    }
}

My question is, how do inner functions behave when they are defined inside a code block other than a function definition? Is the following supposed to be legal? Is it left undefined by the standard?

function outer() {
    if (true) {
        inner();

        function inner() {
            // some code
        }
    }
}

My tests with this JSFiddle seem to indicate that it works on most browsers, including Chrome, Safari, and IE 8–11, but not on Firefox. Is this a bug in Firefox?

Tobia
  • 17,856
  • 6
  • 74
  • 93
  • 1
    This is a case of [function declaration vs function expression](http://stackoverflow.com/questions/336859/var-functionname-function-vs-function-functionname). Function declarations are technically not valid within blocks, browsers will behave differently. It's forbidden in strict mode. – elclanrs Feb 20 '14 at 10:26
  • Try it with if (false) as well, under IE, you might be surprised. I don't know if or when they fixed it. – Marco Mariani Feb 20 '14 at 10:27

1 Answers1

4

They don't - in fact some browsers will fail with that code, especially if you're in strict mode.

When function is executed, it is done so in two steps:

First, all var and function X declarations are found and hoisted to the top. Note that in the case of var x = 1, only the var x part is hoisted, leaving x = 1 in the original place.

Then the code is run.

All var statements are hoisted, even if they are in if blocks. For example:

function test() {
    if( false) {
        var x = 1;
    }
    alert(x); // you may expect ReferenceError, but in fact you get undefined
};

This is safe to do because it's just saying "this variable may exist at some point".

However with functions it is very different, because the function contents are hoisted too. This can cause major problems with functions defined in conditionals, so while some browsers will happily hoist them (leaving the last one defined to be the final definition), others will fail.

function test() {
    if( true) {
        function derp() {alert("True");}
    }
    else {
        function derp() {alert("False");}
    }
    derp(); // an ignorant programmer may expect True,
            // only to find they get False, or an error
}

I hope this makes sense!

Niet the Dark Absol
  • 320,036
  • 81
  • 464
  • 592
  • also http://kangax.github.io/nfe/ - for your last point: Example #4: Function declarations are parsed sequentially and are not affected by conditional blocks – Marco Mariani Feb 20 '14 at 10:33
  • actually, the example I linked is about named function expressions, which makes it even weirder – Marco Mariani Feb 20 '14 at 10:35