How are function declarations handled?
var abc = '';
if(1 === 0){
function a(){
abc = 7;
}
}else if('a' === 'a'){
function a(){
abc = 19;
}
}else if('foo' === 'bar'){
function a(){
abc = 'foo';
}
}
a();
document.write(abc); //writes "foo" even though 'foo' !== 'bar'
This example produces different outputs in Chrome and Firefox. Chrome outputs foo
while FF outputs 19
.
When this question was asked, ECMAScript 5 (ES5) was prevalent. In strict mode of ES5, function declarations cannot be nested inside of an
if
block as shown in the question. In non-strict mode, the results were unpredictable. Different browsers and engines implemented their own rules for how they would handle function declarations inside blocks.As of 2018, many browsers support ECMAScript 2015 (ES2015) to the extent that function declarations are now allowed inside blocks. In an ES2015 environment, a function declaration inside of a block will be scoped inside that block. The code in the question will result in an undefined function error because the function
a
is only declared within the scope ofif
statements and therefore doesn't exist in the global scope.If you need to conditionally define a function, then you should use function expressions.
The ECMA-262 v5 requires implementations to register all function and variable declarations during the first pass when entering any new global or function-level execution context. Chrome is technically doing it right here because it is looking inside the
else
andthen
blocks and registeringa()
prior to execution. Unfortunately it produces the most unreadable results.FF is waiting until it evaluates the if statement before it evaluates and adds function and variable declarations to the current context. BTW. Both browsers do it this way inside catch and finally clauses.
It really is just a matter of two different ECMA implementations dealing with a feature that shouldn't be there to begin with. The scenario at hand shows why function declarations shouldn't be inside control flow statements.
From http://javascriptweblog.wordpress.com/2010/07/06/function-declarations-vs-function-expressions/
In javascript, you have function declaration:
and function expression
Quoting from http://www.adequatelygood.com/2010/2/JavaScript-Scoping-and-Hoisting
So what happened in your first example is that function declaration of
function a()
, gets hoisted to the top of the Javascript scope, thus producing 'foo' even though the if evaluates to falseThink of
var foo
as a normal Javascript statement, it's only executed on the runtime of your javascript, unlikefunction foo()
, that's why the below is valid:Here,
function foo()
is parsed by the parser, puttingfoo()
in the current scope, before attempting to callalert(foo())
http://javascriptweblog.wordpress.com/2010/07/06/function-declarations-vs-function-expressions/