When writing our code, we calculate values and, most times, we need to store them in memory locations for future use. That is why we need variables. In Javascript, we can declare variables in various ways, each type of declaration gives the variable unique characteristics. This article will explore javascript variable types, and how they behave under the following situations:

  • Initialization
  • Availability before declaration
  • Scope
  • Redeclaration
  • Update

Initializing javascript variable types

When we need Javascript to create a variable for us, we carry out a variable declaration using either the var, let or const variable declarations. Once Javascript creates the variable, it initializes the variable with the value we give on the right-hand side of the assignment which makes up the declaration. In the case of variables declared using var or let, initialization is optional. However, an initial value is required for const variables. Without an initial value, Javascript will report a SyntaxError.


var a = 10;     // initial value is 10
let b = 12;      // initial value is 12
const c = 14;      // initial value is 14

var d;      // initial value is undefined
let e;      // initial value is undefined
const f;    // syntax error, initial value required

Availability before declaration

What happens if we try to access a variable before we declare it in code? let and const variables require that they be declared first before any attempt to access them. The next example shows what will happen when we try to access a let variable before it has been declared.


// Try to display the contents of variable 'num'
console.log(num)

// Now declare 'num' with let
let num;

Output:

ReferenceError: Cannot access 'num' before initialization

Any attempt to access the variable resulted in an error. The same can be said for const variables. The story is however very different for variables declared with var. Notice what happens in the next example.


console.log(num);
var num = 34;
console.log(num);

Output:

undefined
34

From the output, we do not see any error message. Instead, the first console.log() prints undefined, as if num were already declared. Then after num is declared, the next console.log() displays 34. In effect, Javascript creates an uninitialized var declaration before the first access of num, and moves it to the top of the containing scope. This Javascript behaviour is called hoisting. The code behaves like the example code below.


var num;
console.log(num);
var num = 34;
console.log(num);

Scope

Scope determines how accessible a variable is. In Javascript, we could have:

  • Global scope, which means the whole application has access to the variable.
  • Function scope, where all code can access the variable
  • Block scope, where only code within the block (including nested blocks) can access the variable

Variables declared with var have function scope because they are accessible throughout the function in which the declaration appears. However, such variables are not accessible outside the function, and any attempt to access them causes a ReferenceError to occur during runtime. See the next example.


function test () {
    var msg = "This is a message from test function";

    // display the contents of 'msg'
    console.log("msg = ", msg);

}

// call the 'test' function
test();

console.log("msg = ", msg);     // Error here!!!

Output:

msg = This is a message from test function
ReferenceError: msg is not defined

The above code example raised a ReferenceError because the msg was out of scope. To eliminate this error, we could declare msg before accessing outside test().


function test () {
    var msg = "This is a message from test function";

    // display the contents of 'msg'
    console.log("msg = ", msg);

}

// call the 'test' function
test();

// declare 'another' 'msg' variable
var msg = "This message is outside the test function scope";
console.log("msg = ", msg);     // Ok!!!

Output:

msg = This is a message from test function
msg = This message is outside the test function scope

This time, we do not have an error, as the second console.log() could now find msg outside the function scope.

In summary, var variables are not accessible outside the function they are declared in.

Both let and const variables have block scope. Code outside the scope of where we declared the variables cannot access them. However, code inside the scope and nested scopes can access let and const variables we declare within a scope. The next example demonstrates this.


{
    // declare the variable here
    var greet = "Hello";
    let name = "Fred";
    const pi = 3.141;

    {
        // accessing through nested scope
        console.log("nested block scope greet = ", greet);
        console.log("nested block scope name = ", name);
        console.log("nested block scope pi = ", pi);

    }

    // access in the defined scope
    console.log("main block scope greet = ", greet);
    console.log("main block scope name = ", name);
    console.log("main block scope pi = ", pi);
    
}

// access out of the defined scope
console.log("out of block scope greet = ", greet);
console.log("out of block scope name = ", name);
console.log("out of block scope pi = ", pi);

Output:

nested block scope greet =  Hello
nested block scope name =  Fred
nested block scope pi =  3.141
main block scope greet =  Hello
main block scope name =  Fred
main block scope pi =  3.141
out of block scope greet =  Hello
ReferenceError: name is not defined

The example defines three variables in the main scope; greet, name, and pi. greet is declared with the var keyword, name is declared with the let keyword, and pi is declared with the const keyword.

The console.log() attempts to access the variables from the main block scope, and the nested block scope succeeded. However, when an attempt was made to access the variables outside the scope under which they were declared, only the var variable could be accessed. The let variable name could not be accessed since it is now dead, or out of scope. A similar remark could be made about the const variable pi, and we see it in action if we comment out the line trying to access name


{
    // declare the variable here
    var greet = "Hello";
    let name = "Fred";
    const pi = 3.141;

    {
        // accessing through nested scope
        console.log("nested block scope greet = ", greet);
        console.log("nested block scope name = ", name);
        console.log("nested block scope pi = ", pi);

    }

    // access in the defined scope
    console.log("main block scope greet = ", greet);
    console.log("main block scope name = ", name);
    console.log("main block scope pi = ", pi);
    
}

// access out of the defined scope
console.log("out of block scope greet = ", greet);
// console.log("out of block scope name = ", name);
console.log("out of block scope pi = ", pi);

Output:

nested block scope greet =  Hello
nested block scope name =  Fred
nested block scope pi =  3.141
main block scope greet =  Hello
main block scope name =  Fred
main block scope pi =  3.141
out of block scope greet =  Hello
ReferenceError: pi is not defined

We still get a ReferenceError. We cannot access either let or const variables out of the scope they were defined.

In summary, let and const variables are block-scoped: their lifespan is the scope within which they were defined. Any attempt to access them outside the scope they were defined results in a ReferenceError since at that point, the variable is no more defined.

Redeclaring javascript variable types

The next example shows attempts to redeclare the variables greet, name, and pi within the same scope and a nested scope.


{
    // initial declaration
    var greet = "Hello";
    let name = "Fred";
    const pi = 3.14;

    {
        // redeclaration in nested scope, no problems here
        var greet = "How are you?";
        let name = "Agatha";
        const pi = 3.141;

    }

    // redeclaration in main block scope, let and const will raise error
    var greet = "Hi there";
    let name = "Maggie";
    const pi = 3.14152;

}

Javascript will view the lines let name = "Maggie"; and const pi = 3.14152; as syntax errors since they have already been declared. However, redeclaring var does not raise a syntax or runtime error. So, redeclaration is only allowed for let and const variables when they are done within different scopes. Redeclaration does not affect the value contained in a var variable unless we assign a new value. Check out the next example for a demo of this.


var fruit = "cherry";
console.log("First declaration of fruit contains: ", fruit);
var fruit;
console.log("Second declaration of fruit without initialization contains: ", fruit);
var fruit = "apple";
console.log("Third declaration of fruit with initialization contains: ", fruit);

Output:

First declaration of fruit contains:  cherry
Second declaration of fruit without initialization contains:  cherry
Third declaration of fruit with initialization contains:  apple

Updating javascript variable types

Once we declare const variables, they cannot be updated. We can see this in the following example code.


var age = 12;   // declare 'age' with var
age = 23;       // update: no problem

let city = "Mumbai";    // declare 'city' with let
y = "Hyderabad";        // update: no problem

const e = 2.81;        // declare 'e' with const
e = 2.818;             // update: error!!!

Output:

TypeError: Assignment to constant variable.

The line e = 2.818; that attempts to update the variable e raises a TypeError at runtime. var and let, on the other hand, do not have any problems with updates.

Conclusion

We have considered the three types of variables that can be declared in Javascript; var, let and const. We considered the behaviour of each with respect to:

  • Initialization: const variables must be initialized before use. When not specified for let and var, the initial value is undefined.
  • Availability before declaration: let and const must be declared before accessing them. var variables are hoisted when Javascript encounters an access attempt before the variable declaration.
  • Scope: let and const variables are block-scoped and available within the scope they are defined, including nested scopes. Variables declared with var are available throughout the function in which their declaration is found, no matter which inner scope the declaration is found.
  • Redeclaration: let and const variables can only be redeclared in nested block scopes. var variables, however, do not have this limitation, as they can be redeclared even within the same scope.
  • Update: Once declared and initialized, const variables cannot be updated. let and var variables can be updated after declaration.

Thanks for reading the tutorial to the end. We hope you have been able to differentiate between the three kinds of variable declarations in Javascript. You can continue your learning by exploring more of our Javascript articles.