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,
No. The include guard prevents a header from being included more than once.
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.
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.
Yes, a function can be used as a variable value.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With