DEV Community

Cover image for JS Variables 101: Var, Let and Const
Harsh Choudhary
Harsh Choudhary

Posted on • Updated on

JS Variables 101: Var, Let and Const

Introduction

Yet another blog explaining Var, Let and Const but I promise this is the only one you need.

ECMASCRIPT2015, also known as ES6 introduced a lot of awesome features. One of the features was the addition of let and const for declaring variables. Previously developers used var for variable declaration, so what was the need of bringing new ones?

If you don't know what let and const brings to the table and how are they different from each other, this blog post is for you. I will compare them based on usage, scope, and hoisting.

Var

Before the introduction of ES6, the only way to define variables in JavaScript was to use the var keyword. For many years, it worked fine, however var differs from other programming languages in terms of variable scoping leading to unwanted bugs that are hard to track.

The below code example demonstrates the declaration of a variable with the var keyword:

var declaredWithVar = "welcome to the blog";
console.log(declaredWithVar);  //welcome to the blog
Enter fullscreen mode Exit fullscreen mode

Scope

The Scope refers to the present context of code, which decides the accessibility of the variables.
The scope is of two types Global and Local:

  • Variables that are declared outside of a block are known as Global variables.
  • Variables that are declared inside of a block are known as Local variables.

The variables declared with var are globally scoped when declared outside a function. Any variable declared with var outside of a function block is accessible across the whole window.

var is a function scoped when it is declared within a function which means that it is accessible within that function only.

Look at the example below to understand further:

var globalScopedVar = "declared globally"

function varScopeCheck(){
  var scopingOfVarInFunc = "declared inside function"
  console.log(scopingOfVarInFunc)
}

console.log(scopingOfVarInFunc) //Uncaught ReferenceError: scopingOfVarInFunc is not defined
console.log(varScopeCheck()) //declared inside function
console.log(globalScopedVar) //declared globally
Enter fullscreen mode Exit fullscreen mode

As you can see, we cannot access scopingOfVarInFunc outside of the function as the variable is locally scoped but we can access the globalScopedVar as it is globally scoped.

var can also be redeclared and updated.

This means the value of the variable can be updated by reinitializing and the variable declared with the var keyword can be declared again and again with the same or different values.

Look at the example below to understand further:

var declaredVar = "First time"
var updatedVar = "Old value"

var declaredVar = "Second time"
updatedVar = "New value"

console.log(declaredVar) // Second Time
console.log(updatedVar) // New value
Enter fullscreen mode Exit fullscreen mode

Hoisting

Hoisting is the process by which the interpreter allocates memory for variable and function declarations prior to executing the code. This allows us to use a variable before it has been declared and initialized.

For example:

 console.log(hoistedVar); //undefined
 var hoistedVar = "I'll be hoisted"
Enter fullscreen mode Exit fullscreen mode

why undefined? why not defined error?
var variables are hoisted to the top of the scope and initialized with the value undefined.

Problem with var

var nameUsingVar = "Michael"
if(true){
  var nameUsingVar = 'Mike instead'
}
console.log(nameUsingVar) // Mike instead
Enter fullscreen mode Exit fullscreen mode

In the above code example, global scoped nameUsingVar is replaced by the block-scoped nameUsingVar and we get the unexcepted value. Well, it is not a problem if it's intentional but imagine managing your variables after 1000s of lines of code. This will become tricky to work with and cause a lot of bugs in your code.

That is why let and const were introduced and widely used.

Let

let came as an improvement over var by being block-scoped which solves the problem discussed above.

The below code example demonstrates the declaration of a variable with the let keyword:

let declaredWithLet = "I am preferred over var";
console.log(declaredWithLet);  //I am preferred over var
Enter fullscreen mode Exit fullscreen mode

Scope

Variables declared with let are block-scoped which means that a variable declared in a block with let is only available for use within that block. Variables declared outside blocks are global scoped.

Let's understand it with an example:

let globalScopedLet = "declared globally"

function letScopeCheck(){
  let scopingOfLetInFunc = "declared inside function"
  console.log(scopingOfLetInFunc)
}

console.log(scopingOfLetInFunc) //Uncaught ReferenceError: scopingOfLetInFunc is not defined
console.log(letScopeCheck()) //declared inside function
console.log(globalScopedLet) //declared globally
Enter fullscreen mode Exit fullscreen mode

It solves the problem with var:

let nameUsingLet = 'Michael'
if(true){
    let nameUsingLet = 'Mike'
}
console.log(nameUsingLet) //Michael
Enter fullscreen mode Exit fullscreen mode

As you can see, we get the expected output as it is block scoped.

let cannot be re-declared but can be updated within a scope block.

let nameUsingLet = 'Michael'

let nameUsingLet = 'Mike'
//SyntaxError: Identifier 'greeting' has already been declared

if(true){
  /* This is a different scope, so redeclaration here is ok.*/
    let nameUsingLet = 'Michel'
    console.log(nameUsingLet) //Michel
}

console.log(nameUsingLet) //Michael
Enter fullscreen mode Exit fullscreen mode

Hoisting

let declarations are hoisted but it's different from var.

console.log(variableUsingLet); // ReferenceError: Cannot access 'a' before initialization
console.log(variableUsingVar); // prints undefined as expected
let variableUsingLet = 10;
console.log(variableUsingLet); // 10
var variableUsingVar = 15;
console.log(window.variableUsingLet); // undefined
console.log(window.variableUsingVar); // 15
Enter fullscreen mode Exit fullscreen mode

It looks like let isn't hoisted, but it is, let's understand:
Both variableUsingLet and variableUsingVar are actually initialized as undefined in hoisting stage. But variableUsingVar is inside the storage space of GLOBAL, and variableUsingLet is in a separate memory object called script, where it can be accessed only after assigning some value to it first ie. one can access variableUsingLet only if it is assigned. Thus, it throws a ReferenceError.

Temporal Dead Zone: Time elapsed since the let variable was hoisted until it was initialized with a value.

So any line till before "let variableUsingLet = 10" is the Temporal Dead Zone for variableUsingLet.
Since variableUsingLet is not accessible on global, it's not accessible in window/this also.
ReferenceError is thrown when variables are in the Temporal Dead Zone, SyntaxError doesn't even let us run a single line of code.

Finally, let’s learn about const.

Const

Just like the name, const variables are constant, they cannot be redeclared or updated and if we try to do so, we will get an error.

With only var, the way to signify a constant variable was to write the variable name in all caps but it still could be updated and redeclared. const solves this problem along with var scoping problem.

const variableUsingConst = 10;
variableUsingConst = 20;
console.log(variableUsingConst)
//TypeError: Assignment to constant variable.
Enter fullscreen mode Exit fullscreen mode

Scope

It is also block-scoped and works similarly to let.

const nameUsingConst = 'Michael'
if(true){
    const nameUsingConst = 'Mike'
}
console.log(nameUsingConst) //Michael
Enter fullscreen mode Exit fullscreen mode

Hoisting

It is similarly hoisted as let.

console.log(variableUsingConst); // ReferenceError: Cannot access 'variableUsingConst' before initialization
const variableUsingConst = 10;
console.log(variableUsingConst); // 10
Enter fullscreen mode Exit fullscreen mode

Conclusion

Keyword Scope Updateable Redeclareable Hoisted
var Function scope Yes Yes Yes
let Block scope Yes No No
const Block scope No No No
  • Try using const wherever possible.
  • If not use let, Avoid var.
  • Declare and initialize all variables with let to the top to avoid errors and shrink the Temporal Dead Zone window to zero.

Discussion (0)