Skip to content

Instantly share code, notes, and snippets.

@rezavai92
Created June 8, 2021 07:27
Show Gist options
  • Save rezavai92/d545b0693a891b2d36129a2536178449 to your computer and use it in GitHub Desktop.
Save rezavai92/d545b0693a891b2d36129a2536178449 to your computer and use it in GitHub Desktop.

No more Confusion with Var, Let and Const

There are so many programmers who claim to love javascript, code in javascript, eat javascript and also sleep with javascript. But there is no such programmer who never had to pass a hard time comprehending many of it's features and their unpredictable behavior.The ambiguity around declaration of javascript variables (function and object are also variable) is one of them that can make a developer's life hell if there is a lack of proper understanding on Scopes and variable's lifecycle.

You probably know that var,let and const are used to declare a variable in javascript. To remind you, there is another kind of declaration in javascript, which requires no keyword at all. We refer such variable as "global". When we call something global, it is supposed to be accessed anywhere by anyone in the code. There are other variables we don't want them to act like global ones. We want them to be limited within certain block of the code. We refer such variable as "local".When i say something like "a certain code block", it brings up another core javascript feature called Scope into the play.But what exactly we have to do with "Scope" and "global/local" stuff while understanding the declaration of variable and apparently the distinction among var , let and const? Keeping this question unanswered for the time being, we will now jump into the next section . I promise, you yourself will be able to answer the question by the end of this blog.

Let's deal with Scope first

Like many other programming languages,Scope is a vital feature of javascript that generally refers to a certain block of the code. Anything declared in a scope is only accessible from within it's own world. outside it, those variables just don't make sense. For example,if we declare anything in a function, we cannot access it outside the function. They are said to be local within their boundary. There are mainly two types of scope in javascript . 1.Global 2. Local When we refer something as global,we actually say that it belongs to the global scope. Any variable declared without any specific keyword belongs to the global scope. For example, "window" is a global object in browser.

For ease of understanding , we could further divide the local scope into two separate scopes. (1)Function Scope (2) Block scope

Everything inside a function is said to have function scope.That means when the function stops being called, it's variables also get vanished.

    function Add(a,b){
        
        var sum = a+b; // sum is a local variable limited to this function
        return sum;
    }
    console.log(Add(2,3)) // returns 5
    
    console.log(sum) // throws reference error.

But what if we write something like this

    function Add(a,b){
        sum = a+b;
        return sum
    }
    console.log(Add(2,3)); // output : 5
    console.log(sum) ; // output : 5

We have seen that , Though we didn't declare "sum" anywhere outside the function , we could still access and print it. shouldn't anything declared inside a function be a "local" variable. Hold on!! we don't do this here. The game has just started!

There is another scope called block-scope.Function scope is also one kind of block scope, but not every block scope is a function scope. Any loop , if/else condition and switch is said to be a block scope.Even if you put anything inside a pair of curly braces , it will have a block scope.

    {
        let a = 5;
        const b = 10;
        console.log(a) // returns 5
        console.log(b) // returns 10
    }
    console.log(a)  //  Reference error, a is not defined.
    console.log(b) // Reference error , b is not defined.

We have seen that, a and b are only accessible inside the block scope. So far,so good! To give you a twist, what if we write something like this

    {
        var a  = 5;
        console.log(a) // returns 5
    }
    console.log(a) // returns 5  

We have declared "a" inside the block and it should have only been limited within it's own world.Then how could we manage to print "a" even though we didn't declare it outside the block?

If you give a closer look at previous two code snippets, you should notice that, we declared a" with "let" in the first example and declared it with "var" in the second.

Now you have probably guessed that there must be something between scope and the declaration with var ,let and const to care about. From now on, we will see the real picture .Are you ready ?

Everything about global variable

When we declare any variable without a keyword like var/let/const it is considered to have global scope and can be accessed from anywhere in the code. As a result, even if you declare such global variable inside a function or loop, they are not bounded to their own block .They just belong to global window (in case of browser) object. Now go back to the example above where we wanted the global varialbe "sum" to be limited to it's function scope and think again.

Everything about "var"

"var" is strictly scoped to the function where it is called. I repeat the word "function". Yes, It is function scoped! So anything we declare with var , should only be accessed from within the function and it should not make any sense outside it. That means, any block scoped variable is still accessible outside the block . This is the reason why we could be able to print such variable outside the block in one of our previous examples. Let's see it again

    {
        var a = 5;
    }
    console.log(a) // returns 5;

In this example, Though we didn't declare variable "a" anywhere outside the block, we could still print it. Remember the rule! anything declared with var is function scoped. But there is no explicit function in the example. Actually everything is considered to be run within the scope of a global object called window [in nodejs it is called "Global"] .When variable "a" comes to know that there is no explicit function where it has been defined, it just gets attached to the window object and start behaving like a global variable. It doesn't necessarily root for the fact that any variable declared with "var" should have global scope, A common confusion among beginners. You see!!

Everything about let and const

Any variable that is declared with let and const are said to have block scopes. So,this type of variable is only accessible from within the block where it is declared. By saying block, function is also included here ..f we try to access any let,const type variable outside it's block , we can't do so.

        {
            let name ="reza";
            let age = 25;
            const nationality = "Bangladeshi"
        }
        we can't access those variables here.

Actually let and const give us much more predictibility and consistency as compared to "var".Some are mentioned below.

  • you cannot redeclare any variable with 'let' within same scope whereas it is possible with "var" .

      { 
         let x = 5;
         let x =7; // it will raise syntax error , as x can't be redeclared within same scope.
      }
    
      var name = "reza";
      var name  = "sakib";
      console.log(name) // sakib
      // name is just redeclared 
    

    hoisting comes into play Both var and the group of let/const actually get hoisted up to the top of respective scope but their declaration mechanism is completely different.We can access any "var" type variable before initializing it in our code (though it returns undefined). lets understand a simple rule regarding hoisting,though hoisting requires a separate blog to be discussed in detail.

    • whenever the code starts running, every varaiable declaration just gets hoisted up to the top of their respective scope. In the very first line, the variable is just introduced to the memory.
    • The next task is to set "undefined" to the variable as initial value. But it really depends on whether we are hoisting a var type variable or let/const type variable. For the case of var, it is set immediately after the first line . For the case of let/const ,it set on the line where the variable is actually defined in code.
    • The final task is to assign the actual value to the variable if it was initialized with any in main code. It is done on the line where variable is actually defined and initialized in main code, for both case of var and let/const.

Let's understand this with example.

  1.  console.log(x) // undefined . not error.
     var x=5;
    
  2.  console.log(x) // throws reference error;
     
     let x=6;
    

For the ease of understanding we can assume that the first code snippet is converted to something like this behind the scene.

      1.just tells the memory to assign a block for x. no value would be set.
      2.x = undefined; 
      3.console.log(x) // undefined;
      4.x = 5

x was hoisted up to the top of the scope. It got introduced to memory and no value had been attached to it so far. In the next line , it was set to "undefined" .The actual value got attached in the line where "x" was actually initialized in main code.

But in case of let and const, we can assume that hoisting and declaration work this way .

  1. just tells the memory to assign a block for x. no value would be set.
  2. console.log(x) // throws reference error. It hasn't been initialized yet. but javascript engine recognizes "x".
  3. x= undefined;
  4. x= 5;

"let" type variable was hoisted too . But the value "undefined" was set in the line where it was actually defined in main code. As a result, there is no chance to see "undefined" if we console log it before the initialization.The actual value will be assigned immediately after this .

[ Note : Many developers understand hoisting this way even though there is no such mechanism when javascript code is run by the engine. To know the actual fact regarding hoisting , we should know about "Execution Context". I will talk about this in a later blog very soon ].

We have seen that how let and const give us much more predictable result. This is the reason why Ecmapscript2015 introduced this two game changing players to us. With the help let/const declaration we can also ensure self containing behavior of any block and function in our code. For example :

    let a =5;
    {
        let a = 10;
        console.log(a) // returns 10
    }
    console.log(a) // returns 5

This is really predictable, right ? We just decalared "a" at two places. a=5 is in the global scope.We also declared "a" inside a block and expected it to be different from the previous one. The result is fine.

But if we try to imitate something like this with "var" ,let's see what happens!

    var a= 5
    {
        var a =7;
        console.log(a); // returns 7
    }
    console.log(a) // returns 7

As it is described earlier, variable "a" has function scope. Though we declared "a" at two places and expected them to be different from each other, they both actually belong to the same world/scope . As a result, the declared "a" inside the block is kind of a redeclaration of "a" .In such use cases , this might give us unpredicatable result.

A curious mind will surely be affected by one critical question that why i haven't distinguished "const" from "let" yet.The reason is, i expected you to know the core difference between let and const. To shade more light on it

we can assign value to a let type variable multiple times after the declaration.But we cannot do this in case of "const" as it expected to be unchangeable by it's nature.

    let a = 5;
     a = 7  // this is valid

But

    const a =5;
    a =7 // this is not valid

There is a gentleman reminder regarding const type declaration with "object".For example

    const person = {
                name :"reza",
                age : 25
        }
    person.name = "sakib"; // valid;
    person.age =28; // valid;

we can actually change the property of a const type object. what we can't do is, we can't reuse "person" to refer something once after it has been defined with const.

Best Practices

  • Don't mix up "var" with "let" in your code. Stick to one.

  • Though everything will be converted to "var" in the end, it is a good practice to use let and const as much as possible. in modern javascript library like React, developers almost never use "var" in their code.

  • Stop creating global variable without any keyword. If you declare anything with var in the main function, it is automatically attached to the window object. You can also declare anything with "let" and "const" in the main scope if you want it to be global. In that case,it will not be attached to the window object, but still show the same global behavior. Moreover, it works in much predictable manner.

In the end, It is important that we take hoisting and scopes into consideration while understanding the inner mechanism of declaring variables with var , let and const. I will talk about hoisting in much more detail in a different blog .This blog is written to give you a foundation on variable declaration in javascript so that you can resolve any kind of conufsion around let , var and const. Now challenge yourself with following examples and try to guess output without running the code . If you have troubles regarding understanding them feel free to comment below or reach me here rezaink1996@gmail.com .

[hint : first understand the scope of the variable, then apply hoisting rule]

  1.  var x =5;
     if(x===5){
         let x =7;
     }
     console.log(x) 
     what will be the output ? 
    
  2.  var x = "game";
     function demo (){
         if(x==="game"){
         x="cricket"
     }
         else if (x=="music"){
             x = "rock"
         }
         else{
             x = "javascript";
         }
         console.log(x)
         var x ="music";
     }
     
     demo() // what will be printed ?
    

To sum it up, I kept one question unanswered in a section above and promised that you should be able to answer it yourself. Let me know if i kept my promise or not in the comment section .

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment