JS Variables 101: Var, Let and Const
Harsh Choudhary
Posted on January 21, 2022
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
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
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
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"
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
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
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
It solves the problem with var
:
let nameUsingLet = 'Michael'
if(true){
let nameUsingLet = 'Mike'
}
console.log(nameUsingLet) //Michael
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
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
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.
Scope
It is also block-scoped and works similarly to let
.
const nameUsingConst = 'Michael'
if(true){
const nameUsingConst = 'Mike'
}
console.log(nameUsingConst) //Michael
Hoisting
It is similarly hoisted as let
.
console.log(variableUsingConst); // ReferenceError: Cannot access 'variableUsingConst' before initialization
const variableUsingConst = 10;
console.log(variableUsingConst); // 10
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
, Avoidvar
. - Declare and initialize all variables with
let
to the top to avoid errors and shrink the Temporal Dead Zone window to zero.
Posted on January 21, 2022
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.