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.
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:
1var declaredWithVar = "welcome to the blog";
2console.log(declaredWithVar); //welcome to the blog
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:
1var globalScopedVar = "declared globally"
2function varScopeCheck(){
3 var scopingOfVarInFunc = "declared inside function"
4 console.log(scopingOfVarInFunc)
5}
6console.log(scopingOfVarInFunc) //Uncaught ReferenceError: scopingOfVarInFunc is not defined
7console.log(varScopeCheck()) //declared inside function
8console.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:
1var declaredVar = "First time"
2var updatedVar = "Old value"
3var declaredVar = "Second time"
4updatedVar = "New value"
5console.log(declaredVar) // Second Time
6console.log(updatedVar) // New value
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:
1console.log(hoistedVar); //undefined
2 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`.
The Problem with var1var nameUsingVar = "Michael"
2if(true){
3 var nameUsingVar = 'Mike instead'
4}
5console.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` 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:
1let declaredWithLet = "I am preferred over var";
2console.log(declaredWithLet); //I am preferred over var
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:
1let globalScopedLet = "declared globally"
2function letScopeCheck(){
3 let scopingOfLetInFunc = "declared inside function"
4 console.log(scopingOfLetInFunc)
5}
6console.log(scopingOfLetInFunc) //Uncaught ReferenceError: scopingOfLetInFunc is not defined
7console.log(letScopeCheck()) //declared inside function
8console.log(globalScopedLet) //declared globally
It solves the problem with `var`:
1let nameUsingLet = 'Michael'
2if(true){
3 let nameUsingLet = 'Mike'
4}
5console.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.
1let nameUsingLet = 'Michael'
2let nameUsingLet = 'Mike'
3//SyntaxError: Identifier 'greeting' has already been declared
4if(true){
5 /* This is a different scope, so redeclaration here is ok.*/
6 let nameUsingLet = 'Michel'
7 console.log(nameUsingLet) //Michel
8}
9console.log(nameUsingLet) //Michael
`let` declarations are hoisted but it's different from `var`.
1console.log(variableUsingLet); // ReferenceError: Cannot access 'a' before initialization
2console.log(variableUsingVar); // prints undefined as expected
3let variableUsingLet = 10;
4console.log(variableUsingLet); // 10
5var variableUsingVar = 15;
6console.log(window.variableUsingLet); // undefined
7console.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.
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.
1const variableUsingConst = 10;
2variableUsingConst = 20;
3console.log(variableUsingConst)
4//TypeError: Assignment to constant variable.
It is also block-scoped and works similarly to `let`.
1const nameUsingConst = 'Michael'
2if(true){
3 const nameUsingConst = 'Mike'
4}
5console.log(nameUsingConst) //Michael
It is similarly hoisted as `let`.
1console.log(variableUsingConst); // ReferenceError: Cannot access 'variableUsingConst' before initialization
2const variableUsingConst = 10;
3console.log(variableUsingConst); // 10
-> 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.
Loves to Code 👨💻 | React Junkie ⚛️ | Learning and sharing 📚
No posts right now.