We can now better define our variables depending on our needs with the introduction of let and const in javascript after ES6.
Before exploring the let
and const
let us first see why there was need for it.
var in javascript
var
are function scoped
, which means they are still accessible outside the block scope even though we have declared them inside it.
//for loop is block scoped for (var i = 0; i < 10; i++) { var iAmInside = "I am available outside of the loop"; } console.log(iAmInside); // I am available outside of the loop //block scope if(true){ var inside = "Inside"; } console.log(inside); // Inside //Function scoped function myFunc(){ var functionScoped = "I am available inside this function"; console.log(functionScoped); } myFunc(); // I am available inside this function console.log(functionScoped); // ReferenceError: functionScoped is not defined
Explanation
In the first and second example, the value of the var
leaked out of the block-scope and could be accessed from outside of it, whereas in the third example var
was confined inside a function-scope and we could not access it from outside.
This happens because of Hoisting.
var
are treated as if they are at the top of the function (or global scope) regardless of where the actual declaration occurs, this is called hoisting. For a demonstration see the following example.
var inside; // hoisted on the top of the function. As there is no function so it is present in the global scope. //block scope if(true){ var inside = "Inside"; } console.log(inside); //Inside //Function scoped In this case value is hoisted inside the function function getValue(condition) { if (condition) { var value = "blue"; return value; } else { // value exists here with a value of undefined return value; } // value exists here with a value of undefined } console.log(getValue(true)); // blue console.log(getValue(false)); // undefined //While execution it is hoisted like this internally function getValue(condition) { var value; //value is hoisted as there is no value attached, so it is undefined. if (condition) { var value = "blue"; return value; } else { // value exists here with a value of undefined return value; } // value exists here with a value of undefined } console.log(getValue(true)); // blue console.log(getValue(false)); // undefined
Block-Level Declarations in javascript
Block or lexical scopes are the boundaries in which declared variables are not accessible outside it. This means the variables declared inside it are available inside given block and its sub-blocks.
Many c-based languages work with block scoping and with its introduction in ES6 will bring the same flexibility to the Javascript.
Block are indicated by {
and }
characters.
let in javascript
let
are declared same as var
but it limits the variable scope to the given block. That is why we should declare let
at the top of the block so that is accessible throughout the block and its sub-blocks.
Example
function getValue(condition) { if (condition) { let value = "blue"; // accessible inside the given scope only return value; } else { // value doesnot exits here return value; } // value doesnot exits here } console.log(getValue(true)); // blue console.log(getValue(false)); // ReferenceError: value is not defined let x = 10; if(x == 10){ let x = 11; console.log(x); //11 value of x inside if block } console.log(x); //10 value of x
No Redeclaration's
We cannot redeclare a given variable with the same name again in the given block. Doing so will result is an error.
var c = 0; let c = 0; //SyntaxError: Identifier 'c' has already been declared var c = 10; if(c == 10){ let c = 11; console.log(c); //11 This will work as it is declared in another scope }
const in javascript
Like let
const
is also block scoped. But it differs from the fact that their variable cannot be redeclared or change by re-assigning the value. The value remains Constant.
const abc = "XYZ"; let abc; //SyntaxError: Identifier 'abc' has already been declared abc = "pqr"; //TypeError: Assignment to constant variable.
For this reason the const
variable should be initialised while declaring.
//Should be initialised while declaring const XYZ; //SyntaxError: Missing initializer in a const declaration
Just like let
, const
is also blocked scoped.
if(true){ const a = "I am inside"; console.log(a); // I am inside } console.log(a); //ReferenceError: a is not defined
However, the value a constant holds may be modified if it is an object.
const person = { name: 'Prashant', age: 25, } person.age = 26; console.log(person.age); // 26
const
declarations for objects do not prevent modification of those objects. A const declaration prevents modification of the binding and not of the value of the binding.
But this will result in the error.
const person = { name: 'Prashant', age: 25, } person = 26; console.log(person); // TypeError: Assignment to constant variable.
The Temporal Dead Zone (TDZ)
According to MDN:
In ECMAScript 2015, let bindings are not subject to Variable Hoisting, which means that let declarations do not move to the top of the current execution context. Referencing the variable in the block before the initialization results in a ReferenceError (contrary to a variable declared with var, which will just have the undefined value). The variable is in a “temporal dead zone” from the start of the block until the initialization is processed.
function do_something() { console.log(bar); // undefined console.log(foo); // ReferenceError: foo is not defined var bar = 1; let foo = 2; } do_something();
The Temporal Dead Zone and typeof
Using the typeof operator to check the type of a variable in it's tdz will throw a ReferenceError
. But for the undeclared variables it will throw undefined
.
console.log(typeof iAmNotDeclared) // undefined console.log(typeof iAmDeclared)// ReferenceError: iAmDeclared is not defined //Above this is it's temporal dead zone let iAmDeclared = 10;
Temporal Dead Zone with lexical or block scoping
function test(){ var foo = 33; if (true) { let foo = (foo + 55); // ReferenceError: foo is not defined } } test();
Due to lexical or block scoping let foo = (foo + 55)
access the foo
of the current block that is inside the if
condition. It does not access the var foo = 33;
as let
is blocked scope. let foo
is declared but it is not initialized that is why it is still in temporal dead zone.
When to use Var, Let and Const
There is no as such rule stating where to use each of them, Everyone has different opinions.
But according to the properties of these three, it should be used as follows.
- Use
var
for top-level variables that are shared across many (especially larger) scopes. let
can used for localized variables in smaller scopes.- If there is no need to re-assign any variable. like
const PI = 3.14;
then useconst
.
Do your own research and figure out which one to use where.
Pavan says:
Well structured!! Great article. With this I was clear about temporal dead zone and const var modifications.
Ankush Ladani says:
That’s Awesome article. Thank you.