Why does shadowed variable evaluate to undefined w

2019-01-19 15:37发布

问题:

Consider the following piece of code:

<html><head></head>
<body>
    <script type="text/javascript">
        var outside_scope = "outside scope";
        function f1() {
            alert(outside_scope) ;
        }
        f1();
    </script>
</body>
</html> 

The output for this code is that the alert box displays the message "outside scope". But, if I slightly modify the code as:

<html><head></head>
<body>
    <script type="text/javascript">
        var outside_scope = "outside scope";
        function f1() {
            alert(outside_scope) ;
            var outside_scope = "inside scope";
        }
        f1();
    </script>
</body>
</html> 

the alert box displays the message "undefined". I could have understood the logic if it displays "undefined" in both the cases. But, that is not happening. It displays "undefined" only in the second case. Why is this?

Thanks in advance for your help!

回答1:

In the first case, your code is accessing the global variable "outside_scope", which has been initialized to "outside scope".

Javascript has function level scope, so in the second case it is accessing the function scoped variable "outside_scope", but it has not yet been initialized at the time of the alert box. So it displays undefined.



回答2:

Variables are subject to hoisting. This means that regardless of where a variable is placed within a function, it is moved to the top of the scope in which it is defined.

For example:

var outside_scope = "outside scope";
function f1() {
    alert(outside_scope) ;
    var outside_scope = "inside scope";
}
f1();

Gets interpreted into:

var outside_scope = "outside scope";
function f1() {
    var outside_scope; // is undefined
    alert(outside_scope) ;
    outside_scope = "inside scope";
}
f1();

Because of that, and the function only scope that JavaScript has, is recommended to declare all the variables at the top of the function, to resemble what will happen.



回答3:

JavaScript has function scope, not block scope.

In the second case, the declaration of outside_scope is hoisted up to the top of the function (but the assignment isn't).

This is a great example of why JavaScript code is easier to read if you put all your variable declarations up at the top of the function. Your second example is equivalent to:

function f1() {
    var outside_scope;
    alert(outside_scope);
    outside_scope = "inside scope";
}

and you can probably now understand why you're getting "undefined."



回答4:

In the second example the local variable exists for the entire function scope. It doesn't matter that you defined it after the alert, it exists for the entire function.

However, the actual assignment doesn't occur until after the alert, hence the "undefined".



回答5:

that's an interesting case.

in the first example, you have defined a 'global' variable. it has global scope and is therefore accessible in any function/object for the execution.

in the second example, you have 'blocked' the global variable with the function scope variable, but since it hasn't been initialised yet at the time of the alert, it returns 'undefined'.

i agree this isn't the most intuitive quirk, but it does make sense.



回答6:

This is due to something called the hoisting of variable declarations.

Basically, JavaScript separates a variable declaration in two, leaving the assignment where you did the declaration and hoisting the actual declaration to the top of the function:

var f1 = function ()  {
   // some code
   var counter = 0;
   // some more code
}

var f2 = function () {
   var counter; // initialized with undefined
   // some code
   counter = 0;
   // some more code
}

On run-time, f1() gets translated into f2(). I wrote an in depth blog post about this here. I hope this helps you understand what happens in your code.

This is also the reason, it is recommended to declare your variables at the top of a function in JavaScript. It helps you understand what the code does, when it runs.