Redeclare JavaScript Variable

In the following code:

var greeting = "hi";

function changeGreeting() {
    if (greeting == "hi") {
        var greeting = "hello";
    }

    alert(greeting);
}

changeGreeting();‚Äč

...greeting is undefined. However if I remove the var and change changeGreeting() to this:

function changeGreeting() {
    if (greeting == "hi") {
        greeting = "hello";
    }

    alert(greeting);
}

...I get "hello" as expected.

I would never redeclare a variable like this in my code, but why does this happen?

Answers


JavaScript variables have function scope. Thus, the very presence of var greeting inside the function will declare a local greeting variable, which will be undefined at the time of its mention in if condition: the global variable will not be visible inside the function, being overshadowed by the local one. Therefore, the if does not happen, the assignment to hello doesn't happen, the variable is still undefined.

In the second example, you're using the global variable throughout, it is not overshadowed by a local variable (because, no var greeting inside the function), and things work as you expect.


It's very simple: JS hoist the Variable declarations to the top of the current scope, but any operations (including assignments) aren't hoisted (within the same scope, see second case explanation), of course. So your snippet is translated to

(function()
{
    var currentSize;//undefined
    if (currentSize == 'hi')//always false
    {
        currentSize = 'hello';//assignment that will never be
    }
    alert(currentSize);//alerts undefined, of course
}());

By leaving out the var, proceeds to scope scanning (checking for the variable being declared in the global scope). Sadly, in doing so, the context of the first use of the var is lost (inside a branch), and the assignment is hoisted, too. An implied global is translated to:Thank god this isn't true. I assumed it was, because I tested a couple of things in the console that seemed to corroborate this. In this case @amadan is right: you're using the global variable (called greeting in your snippet by mistake when I posted this). I'm going to leave the code below (corrected it) to show what implied globals actually are, hoping it helps somebody sometime in understanding scopes/scope-scanning in JS.

var currentSize = 'hello';
//well, actually implied globals can be deleted, so it's more like
Object.defineProperty(this,'currentSize',{value:undefined,
                                          writable:true,
                                          enumerable:true,
                                          configurable:true});
(function()
{
    if (currentSize == 'hi')//always false
    {//this still doesn't get executed
        currentSize = 'hello';//assignment that will never be
    }
    alert(currentSize);//alerts undefined
}());

In your first code snippet, you're checking global variable, which doesn't exist -> doesn't pass if condition.

Check out this on javascript scopes and how to work with variables Javascript garden - function scopes


Need Your Help

Why JS function name conflicts with element ID?

javascript html

I've got two almost identical simple JS fiddles calling a function on select change. Function name is the same as select ID in both cases, but for some reason the first fiddle works just fine, and ...

How to Generate a Sequence Diagram from Java Source Code

java uml reverse-engineering sequence-diagram

I have a question about generating sequence diagram from Java source code. When I googled I saw someone told to use visual paradigm (VP), but it does not generate sequence diagram for me. Some step...