Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does second function declaration win even though I return before it?

Tags:

javascript

I have the following JavaScript code:

(function() { 
    function f(){ alert(1); }
    return f();
    function f(){ alert(2); }
})();

Can you explain why the alert pops up with 2 and not 1?

Thanks,

like image 611
Andreas Avatar asked Nov 07 '11 11:11

Andreas


People also ask

Can a function be declared more than once?

No. The include guard prevents a header from being included more than once.

Should I use function declaration or expression?

Summary. In short, use function declarations when you want to create a function on the global scope and make it available throughout your code. Use function expressions to limit where the function is available, keep your global scope light, and maintain clean syntax.

What is the point of a function declaration?

A function declaration tells the compiler about a function's name, return type, and parameters. A function definition provides the actual body of the function. The C standard library provides numerous built-in functions that your program can call.

Can we use a function as a variable value yes or no?

Yes, a function can be used as a variable value.


1 Answers

This gets into what happens when execution enters a function: Leaving out a lot of detail, all function declarations (the style you've used) are processed, and only after that does step-by-step code execution occur. So your return statement has no impact on which function declaration is chosen. And the declaration chosen is always the last one in source code order (this is covered — in wonderfully turgid prose — in Section 10.5 of the specification).

The result would be fundamentally different if you used function expressions, which are evaluated as part of step-by-step code:

(function() { 
    var f;
    f = function(){ alert(1); };
    return f();
    f = function(){ alert(2); };
})();

This code is technically incorrect (because you have code following a return that will always be followed), but it illustrates the difference: You see the alert(1) happen rather than the alert(2), because those expressions are not evaluated until they're reached.

You can read more about what happens when execution enters a function (declarations aren't the only thing that are done prior to the first step-by-step code) in Sections 10.4.3 and 10.5 of the specification.


And with your new knowledge, a quiz: What happens here? (Note: Never do this.)

function foo() {

    if (true) {
        function bar() {
            alert(1);
        }
    }
    else {
        function bar() {
            alert(2);
        }
    }

    bar();
}

foo();

The answer is: It varies, don't do that. Some engines will use the first bar, other engines will use the second, and others will call it a syntax error. This is because this actually is an error, and so engines are free to do what they think best. If you look closely at the language grammar, you'll see that it's invalid to put function declarations inside branches within their immediately-containing scope. They must be at the top level of that scope. With your new understanding of declarations, the reason should be obvious: They're not related to the flow of execution within the scope, and so naturally you can't choose them based on that flow of execution.

So what happens in the real world? Sadly, usually not an error if you're in "loose" mode (not strict). Some engines (Chrome's V8 for example, as of this writing) will ignore the flow control statements and just pick the last function declared (and so you get the counter-intuitive result that the second bar function is used), other engines (Firefox's SpiderMonkey, IE11's JScript) effectively rewrite your code on the fly turning those declarations into expressions instead, and so you get the first bar. E.g., it will vary by engine. The good news is that if you try this in strict mode, all three of those (V8, SpiderMonkey, and IE11's JScript) will fail rather than picking one (V8 and SpiderMonkey with nice clear error messages in the console; JScript with just the surprising "bar is undefined", but...).

If you want to do something like the above, but valid and consistent across engines, use expressions:

function foo() {
    var bar;

    if (true) {
        bar = function() {
            alert(1);
        };
    }
    else {
        bar = function() {
            alert(2);
        };
    }

    bar();
}

foo();

There's a fun exploration of this on kangax's Named Function Expressions Demystified page.

like image 183
T.J. Crowder Avatar answered Oct 20 '22 18:10

T.J. Crowder