Here are the simple code:
{
function a() {}
a = "test";
}
console.log(a);
I expected to get "test" but got "ƒ a() {}" in console. Why is that? Can anyone explain this behaviour?
Here are the simple code:
{
function a() {}
a = "test";
}
console.log(a);
I expected to get "test" but got "ƒ a() {}" in console. Why is that? Can anyone explain this behaviour?
3
Answers
It’s because you are only re-assigning "a" in local scope. Run this code and look at the console logs to see what exactly is going on:
If you look at the official docs, it states: "Function declarations in JavaScript are hoisted to the top of the enclosing function or global scope." function#hoisting
Since there is no enclosing function, just a block, the function gets hoisted to the global scope.
I couldn’t find any official documentation regarding the exact behaviour of implicit globals. (Best I could find is: var#implicit_globals_and_outer_function_scope Therefor I can only assume that it searches for the closest scope to reassign. As the function is declared in local scope of the block, it only reassigns the local scoped function declaration and not the one hoisted to global scope.
Our code works in the non-strict mode so some quirk things happen (it’s legacy).
Please use the strict mode only, which throws an error and prohibits such strange effects that lead to bugs.
The strict mode:
Sloppy mode vs Strict Mode
It has to do with strict and quirks mode in modern browsers, and that the effect of defining a function (which used to be always hoisted to the scope of the the function it’s in) inside a block statement.
a
is modified by the assignment. Outside the blocka
remains undefined.a
inside the block. The practical effect is that the hoisted function definition remains in place outside the block, while inside the block, the local value ofa
is updated by the assignment.I believe the behavior in quirks mode was arrived at to maintain some similarity with browser behavior prior to the introduction possibly block scoping variables – _if you don’t overwrite the function name with
Bottom line? _The handling of defining functions within the block of a conditional or loop statement (using
{
and}
delimiters) prior to ES5 was not standardized. Many people would not have done it for stylistic reasons – why define a function name that will be hoisted inside a block. Which left the door open to not hoist function names outside the block in strict mode.Moral of the story – don’t write serious code in sloppy mode 🙂