What you have encountered is probably a bug/inconsistency that is originated from function hoisting, function expression Vs function declaration.
TLDR: NEVER wrap function expressions inside blocks as you did!
(in earlier browser version caused a lot of bugs, but still now is a no no)
Premise: in JS functions are hoisted at the top of the scope, this means this is perfectly valid JS
foo(); // 'a'
function foo() {
console.log('a');
}
Then you have block scoping. How do you expect you program to behave if the function is enclosed inside a different block? Should the function be evaluated?
Let’s look at some examples:
1: in a valid block scope
foo() // typerror: foo is not a function
if(true) {
function foo() {
console.log('a')
}
}
2: however this works
if(true) {
function foo() {
console.log('a')
}
}
foo() // 'a'
3: in an invalid block scope:
if(false) {
function foo() {
console.log('a')
}
}
foo() // typeError foo is not a function
Now looking at your blocked example why it works? (I have no idea)
function main () {
{
function print () {
console.log('a');
}
print();
if (1 > 0) {
function print () {
console.log('b');
}
print();
}
print();
}
}
main(); // aba
I’d expect an error of some sort, all I got is a warning from the linter.
But looks at what happens if you switch from function declaration to function expression:
(Note that function expressions are not hoisted)
function main () {
{
var p = function print () {
console.log('a');
}
p();
if (1 > 0) {
var p = function print () {
console.log('b');
}
p();
}
p();
}
}
main(); // a b b
As you can see the result changes.
You can produce different results if you don’t re-declare var p = function print() {...}
This is one of the unfortunate inconsistencies of JS, if it were another language (maybe a compiled one) I’d expect the program to not even compile and scream at me why am I re-declaring function with the same name.
According to the implementation:
FunctionDeclarations are only allowed to appear in Program or FunctionBody. Syntactically, they can not appear in Block ({ … }) — such as that of if, while or for statements. This is because Blocks can only contain Statements, not SourceElements, which FunctionDeclaration is.
If we look at production rules carefully, we can see that the only way Expression is allowed directly within Block is when it is part of ExpressionStatement. However, ExpressionStatement is explicitly defined to not begin with “function” keyword, and this is exactly why FunctionDeclaration cannot appear directly within a Statement or Block (note that Block is merely a list of Statements).
resource:
function declaration
MDN function