Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
161 views
in Technique[技术] by (71.8m points)

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

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,

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...