Demystifying var, let and const

Demystifying var, let and const

ยท

7 min read

Javascript is a dynamically typed language. Dynamically typed languages are those languages, where the type of the variable purely depends on the type of the value that is being stored inside the variable. For example, if the type of the value is a String, then the type of the variable would also be a String.There are currently three ways in which we can declare variables in Javascript. They are - var, let and const. All three are different from each other either with respect of usage, scope or hoisting. Let's try to understand each of these with the help of an example.

Case One - var

Usage

"use strict"
var variableWithVar = 5;
var variableWithVar;

console.log(variableWithVar); // Prints 5

var is a special keyword which is used to declare variables as shown above. Duplicate variable declarations would not cause any error even in strict mode(use strict) and the value would not be lost unless a new value is assigned to that variable.

Scope

In terms of scope, var declarations are function scoped if declared inside a function, otherwise it would be treated as global variables, which are stored inside the global object. These are also added to a list on the internal names [[VarNames]] slot on the global environment record. Function scoped variables are those variables, which would be accessible only inside the functions where they are declared.

// Example One
function varScope() {
  var variableWithVar = 1;
  console.log("Inside Function", variableWithVar);
}
varScope() // Prints 'Inside Function' 1
console.log("Outside Function", variableWithVar) // ReferenceError: variableWithVar is not defined
// Example Two
var variableGlobal = 5;
function varScopeTwo() {
  console.log("Inside Function", variableGlobal);
}
varScopeTwo() // Prints 'Inside Function 5'

In the above code snippets, Example One is a clear example of var being function scoped while Example Two is a clear example of var being a global variable.

Hoisting

In terms of hoisting, all the variables declared using the var keyword will be hoisted. The concept of hoisting is that all the declaration statements will be moved to the top, even before any code is executed. The important thing to remember is that, only the variable declarations will be hoisted and not their values. All the variable declarations after hoisting, will be assigned a value undefined, because of which, it is always recommended to declare the variables before even using it.

console.log(variableWithVar); // Prints 'undefined'
var variableWithVar = 5;

In the above code snippet, at first, Javascript parses the code during which, all the declaration statements will be hoisted. In this case, var variableWithVar will be moved to the top and will be assigned with the value undefined. As there are no more declaration statements, it moves to the code execution phase where it executes the console.log() statement. On execution, it searches for the variable,variableWithVar in the global memory. As soon as it finds it, it passes the value as an argument to the console.log() method. Since the value of variableWithVar was undefined, it prints undefined

Case Two - let

Usage

let variableWithLet = 5;
console.log(variableWithLet); 
let variableWithLet;

// Output
/*
SyntaxError: Identifier 'variableWithLet' has already been declared. (3:4)
*/

let is a special keyword which is used to declare variables as shown above. Duplicate variable declarations would throw error as shown in the above code snippet. Variables declared using let can be re-assigned similar to var.

Scope

In terms of scope, let declarations are block scoped. Blocks are represented with the help of {}. Block scoped variables are those, which would be accessible only inside the blocks where they are declared. In simple terms, any blocks ({}) are turned into a block scope, if any of the variables inside the block are declared using let. Unlike var, let does not create a property in the global object.

// Example One
function exampleOne() {
  let one = 1;
  console.log(one);
}
exampleOne() // Prints 1
console.log(one) // ReferenceError: one is not defined

In the above code snippet, exampleOne is a function, where the body of the function is present inside the {}. Declaring any variables using let inside this function will make it block scoped. console.log(one) throws an error as we are trying to access the variable one outside the block of exampleOne.

// Example Two
{
  let one = 1;
  console.log(one) // Prints 1
}
console.log(one) // Prints ReferenceError: one is not defined

The above code snippet is a clear example which show that let converts any blocks({}) into scoped block where any variables declared using let, can only be accessed inside that block and not anywhere else.

// Example Three
function letScope() {
  let outsideOne = 1;
  if(true) {
    let insideOne = 2;
    console.log(insideOne) // Prints 2
    console.log(outsideOne) // Prints 1
  }
  console.log(insideOne) // Prints ReferenceError: insideOne is not defined
}
letScope()

In the above code snippet, on executing the letScope() function, if(){} statement present inside the function turns to be block scoped as the variables inside the block are declared using let. console.log(insideOne) prints 2, as insideOne is in the same scope. console.log(outsideOne) prints 1 by following the rules of lexical scoping, where the child function can access the variables of it's parent functions. On executing the console.log(insideOne) statement present outside the if block, Javascript throws a reference error as we are trying to access insideOne variable outside the if block.

// Example Four
var one = 1;
let two = 2;

console.log(this.one) // Prints 1;
console.log(this.two) // Prints undefined;

The above code snippet is a clear example which shows that let does not create a property in the global Object.

Hoisting

In terms of hoisting, all the variables declared using the let keyword will be hoisted. During hoisting, all the let declarations moves to the top of the code. Unlike var, let variables cannot be used (read/write) till they are fully initialised. They become fully initialised only when they are initialised with a value. Accessing let variables before initialisation throws a Reference Error.

console.log(one); // ReferenceError: one is not defined
let one = 1;

let variables are said to be inside the Temporal Dead Zone(TDZ) till they are completely initialised. Temporal Dead Zone is the time period in which the variables are declared but are not accessible since they are not set with a value. This happens when let variables are hoisted. var variables on the other hand, are by default set to a value undefined during hoisting.

{ 
  // TDZ of one starts
  console.log(two); // Prints undefined
  console.log(one); // Prints ReferenceError: Cannot access 'one' before initialisation
  var two = 1;
  let one = 2; // TDZ of one ends
}

In the above code snippet, the Javascript engine parses the code and moves all the variable declarations to the top - var two = undefined and let one. This marks the start of TDZ as the variable one is not completely initialised with a value. Now, as the javascript enters the execution phase, it prints undefined for the console.log(two) statement and throws an error for console.log(one) as the let variables cannot be accessed till they are completely initialised.

Case Three - const

Usage

const variableWithConst = 5;
console.log(variableWithConst); // Prints 5
variableWithConst = 6;
console.log(variableWithConst); // Prints TypeError: Assignment to constant variable.

const is a special keyword which is used to declare variables as shown above. Duplicate variable declarations and re-assigning values to a const variable would throw a reference and type error respectively as shown above.

Scope

In terms of scope, const declarations are also block scoped which is same as that of let.

// Example One
function exampleOne() {
  const one = 1;
  console.log(one);
}
exampleOne() // Prints 1
console.log(one) // ReferenceError: one is not defined

In the above code snippet, exampleOne is a function, where the body of the function is present inside the {}. Declaring any variables using const inside this function will make it block scoped. console.log(one) throws an error, as we are trying to access the variable one outside the block of exampleOne.

Hoisting

In terms of hoisting, all the variables declared using the const keyword will be hoisted, which is same as that of let.

console.log(one); // ReferenceError: one is not defined
const one = 1;

The const variables are also said to be inside Temporal Dead Zone(TDZ) till they are completely initialised which is exactly the same as that of let. This happens when const variables are hoisted.

I hope this clears how var, let and const declarations works with respect to usage, scope and hoisting. If you feel this article was useful, please do show your love and share this to your fellow beings via your social media who could make maximum use of this. Always feel free to connect with me on twitter, linkedIn or email.

Until we meet again, The Mallu Dev signing off ๐Ÿ‘‹ Cheers ๐Ÿฅ‚