Search code examples
javascriptfunctionhoisting

Need to understand Javascript function hoisting example


I read the concept of Javascript Hoisting.Its pretty confusing but I saw some examples and got the idea what hoisting actually does.

So basically "Hoisting is JavaScript's default behavior of moving all declarations to the top of the current scope (to the top of the current script or the current function)."

But I am not able to understand the below implementation :

var is_android = true;
if (is_android) {
    function foo() {
        alert('I am Android');
    }
} else {
    function foo() {
        alert('I am NOT Android');
    }
}
foo();

The output shows "I am NOT Android" in alert box.

I want to know why foo() is called from else block even if is_android value is true .

Any help will be appreciated.


Solution

  • tl;dr: Don't use something that looks like a function declaration inside a block, especially not a conditional.


    Fact is, most browsers interpret this piece of code the wrong way. They treat the function definitions as function declarations, even though function declarations are not allowed inside blocks, since a function declaration is not a statement, it's a source element.

    This how it works in general:

    Before the code is even executed, the interpreter looks for all variable and function declarations, not matter where they are, and creates a binding for them in the current/new environment. Then it starts actually executing the code.

    So, assuming that the function definitions are interpreted as declarations, since there are two declarations, the last one wins. Your code basically becomes:

    function foo() {
        alert('I am Android');
    }
    function foo() {
        alert('I am NOT Android');
    }
    var is_android;
    
    is_android = true;
    if (is_android) {
    
    } else {
    
    }
    foo();
    

    Other engines would interpret it differently, but still incorrectly (IMO, see below):

    In the following script, the zero function is never defined and cannot be invoked, because 'if (0)' evaluates its condition to false:

    if (0) {
       function zero() {
          document.writeln("This is zero.");
       }
    }
    

    Note: Some JavaScript engines, not including SpiderMonkey, incorrectly treat any function expression with a name as a function definition. This would lead to zero being defined, even with the always-false if condition. A safer way to define functions conditionally is to define the function anonymously and assign it to a variable:

    if (0) {
       var zero = function() {
          document.writeln("This is zero.");
       }
    }
    

    But in this case, if the function definition truly was interpreted as function expression (similarly to (function zero() { ... })), then the name of the function would not be accessible in the containing scope, and the function would just be lost.