Search code examples
javascriptglobal-variableslocal-variableshoisting

Why a variable defined global is undefined?


I have here a simple function and a global variable.

Why is myname undefined and not the string "global"?

var myname = "global"; // global variable
function func() {
    alert(myname); // "undefined"
    var myname = "local";
    alert(myname); // "local"
}
func();

Is not possible to refer to a outer variable that is define outside the scope of that function? And in this a global variable...

And how I can fix this so I don't get a undefined from a global variable?


Solution

  • You have just stumbled on a js "feature" called hoisting

    var myname = "global"; // global variable
    function func() {
        alert(myname); // "undefined"
        var myname = "local";
        alert(myname); // "local"
    }
    func();
    

    In this code when you define func the compiler looks at the function body. It sees that you are declaring a variable called myname.

    Javascript Hoists variable and function declarations, by moving the declaration to the top of the function.

    Because of hoisting your code is rewritten to the following.

    var myname = "global"; // global variable
    function func() {
       var myname; //declare local variable and assign it undefined
       alert(myname); // "undefined"
       myname = "local"; // assign local var myname to "local"
       alert(myname); // "local"
    }
    func();
    

    This "Covers" the global variable. If you want access to the global variable within the scope of a function use the this keyword.

    var myname = "global"; // global variable
    function func() {
        var myname = "local";
        alert(this.myname); // "global"
        alert(myname); // "local"
    }
    func();
    

    Note that this only works in calling a function not a method or constructor because the this keyword changes what its bound to based on how you call a function.

    EDIT: For completeness

    If you want to get access to global variables in any context regardless of function type then declare a global variable that by convention you never cover.

    var global = this; // in global scope.
    var myname = "global";
    var obj = {f: function () {
        var myname = "local";
        console.log(global.myname);
    }};
    obj.f(); // "global"
    

    Note that this is in method position and the this keyword refers to obj directly and therefore doesn't have myname defined.