Here we will learn to know the different keywords that allow you to declare variables on Javascript: all the differences between var, let and const.
The older generation Javascript developers are used to declare all the variables of their own scripts through the keyword <code>var</code>, since this was the only possibility until the advent of the ECMA6 specification.
This new specification has in fact introduced also the keywords <code>let</code> and <code>const</code>, which act as updates and extensions of the mere concept of <code>var</code>. But what are the real and concrete differences between these identifiers, and why should we use them in our scripts? In this article we will make complete clarity on this important matter.
Consider the following snippet:
var x = 10; var y = 20; var z = 30;
In this way 3 variables are declared (x, y and z) to which values are immediately assigned. But there is one more step to know: the variables declared in this way are considered as global variables , or better, belonging to the global scope .
The scope , in fact, is the answer to why other identifiers were created to construct variables, a question that a less experienced developer could, rightly, ask himself.
Global and local scope
In Javascript, a variable declared with the keyword <code>var</code> belongs to the global object window, and is also accessible as follows:
var x = 10; var p = document.getElementById('demo'); p.innerHTML = window.x;
Use xor window.xis the same thing. A global variable can also be declared and assigned by bypassing the keyword var, becoming also available as an object property window:
y = 20; var p = document.getElementById('demo'); p.innerHTML = window.y;
This particular object-oriented hierarchy is essential for creating more advanced scripts, such as accessing global variables using strings as identifiers.
Now, we know that as in all programming languages, even in Javascript we can declare and use the functions . In functions, however, there is a local scope, which is different from the global scope. Let’s see the following example:
var x = "out"; function faiQualcosa() { var x = "inside"; console.log(x); } faiQualcosa(); // inside console.log(x); // out
As we can see, we declare via the keyword <code>var</code> the variable x both outside the function, in the window object, and inside the function do Something. In this case Javascript has no problem interpreting the two variables, and in fact the global one is not altered.
Things change if we assign a value x in the function without declaring the variable with the keyword <code>var</code>:
var x = "fuori"; function faiQualcosa() { x = "inside"; console.log(x); } faiQualcosa(); // inside console.log(x); // inside
This happens because in this case we did not specify that the variable x must have a local scope. Since global variables are accessible from within the functions, the value of x is altered. The opposite is not true: the variables declared in the functions, therefore having local scope, are NOT accessible from outside the function.
We can therefore say that the variables declared with var have a local / global scope depending on whether they are declared inside or outside the functions.
Block scope
The ECMA2015 specification introduced the block scope. A “block” is defined by curly braces <code>{</code> and <code>}</code> contains portions of code that are “unto itself” relative to the global code.
The biggest and most obvious difference between <code>var</code> and <code>let</code> is right in the scope. A variable declared with <code>var</code>, it has NO block scope . This means that a variable declared in a block using var is also accessible outside the block:
// global code // ... // block { var x = 2; } // x is available
So the following code:
var i = 0; if (true) { var i = 1; } console.log(i); // 1
Rewrite the value of the variable <code>i</code>, which will also be modified outside the block. This behavior is not always desired, especially in the modern JavaScript programming style, in which the block scope can create inconsistencies.
For this reason the identifier was created <code>let</code>, which unlike the previous one, HA block scope. So, a snippet identical to the previous one, but using let, produces the following result:
let i = 0; if (true) { let i = 1; } console.log(i); // 0
Although the variable i is reassigned within the block if, it is not a problem using the let operator, because that assignment is local and referred to the block of membership code, while the external one refers to the block of global code.
The general rule, using let, is described by the following snippet:
{ let x = 2; } // x It is not accessible
var VS let
We see the differences between the use of <code>var</code> and <code>let</code>, enclosed in this analysis.
Block scope
var x = 10; // who x è 10 { var x = 2; // who x è 2 } // who x è 2
var x = 10; // who x è 10 { let x = 2; // who x è 2 } // who x è 10
The difference is abysmal. In the first case, not having a block scope, the variable x is overwritten. In the second case, the global variable x is not affected by the declaration of the local x variable for the block of code in which it is defined through <code>let</code>.
With a bit of practice and good craftsmanship in writing modern JavaScript, using it <code>let</code> in conjunction with <code>var</code> will become increasingly intuitive and simple.
Loop scope
The same functionality just seen is also active in the scope of loops, such as <code>for</code>:
var i = 5; for (var i = 0; i &amp;lt; 10; i++) { // operations } // Qui i è 10
If instead we use let:
let i = 5; for (let i = 0; i &amp;lt; 10; i++) { // operations } // Qui i è 5
In the first case, using var, the loop alters the value of the global variable i. In the second case, using let, we have the loop scope, so the global variable is not touched.
Function scope
var and let both have a local scope for declaration in functions:
function myFunction() { var myName = "John"; // Function Scope } function&amp;nbsp;myOtherFunction() { &amp;nbsp;&amp;nbsp;&amp;nbsp;let&amp;nbsp;myName =&amp;nbsp;"John";&amp;nbsp;&amp;nbsp;&amp;nbsp;// Function Scope }
Global scope
Same with regards to the global scope:
var x = 2; // Global scope let&amp;nbsp;y =&amp;nbsp;2;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// Global scope
However, here there is a difference to be aware of. As we said earlier, the global variables declared with var are accessible via the global window object. However, the same can not be said for variables declared with let, which are NOT accessible via the window object:
var myName = "John"; var p = document.getElementById('demo'); p.innerHTML = window.myName; // okay let myName = "John"; var p = document.getElementById('demo'); p.innerHTML = window.myName; // error
re declaration
Redefine a var variable using the var identifier is allowed (everywhere):
var x = 2; // ora x è 2 var x = 3; // ora x è 3
Redefine a let variable using the let identifier in a different scope (such as blocking) is allowed:
let x = 2; // allowed { let x = 3; // allowed } { let x = 4; // allowed }
Redefining a var variable using the let identifier , in the global scope or in a block scope is NOT allowed:
var x = 2; // allowed let x = 3; // Non allowed { var x = 4; // allowed let x = 5 // Non allowed }
Redefining a let variable using the let identifier , in the global scope or in a block scope is NOT allowed:
let x = 2; // allowed let x = 3; // Non allowed { let x = 4; // allowed let x = 5; // Non allowed }
To redefine a let variable using the var identifier , in the global scope or in a block scope, is NOT allowed:
let x = 2; // allowed var x = 3; // Non allowed { let x = 4; // allowed var x = 5; // Non allowed }
Hoisting
The term hoisting identifies the computation of Javascript in which the variables could be used BEFORE their declaration, since the declarations of the variables, even if placed for example at the end of the script, were “pushed” above, and therefore the procedure was perfectly legal. With the introduction of the indentifier, however, this is no longer true.
With <code>var</code> the keyoword, hoisting is perfectly legal:
// here you can use the variable myName even if its declaration // is carried out later myName = "John"; var p = document.getElementById('demo'); p.innerHTML = myName; // okay // declaration var myName;
With the keyword <code>let</code>, the hoisting is not legal and will result in a <code>ReferenceError</code>, since unlike the var variables that are initialized as <code>undefined</code>, the variables let are not initialized:
// here you CAN NOT use the myName variable if your declaration // is carried out later var p = document.getElementById('demo'); p.innerHTML = myName; // Reference Error // declaration let myName;
const
Now let’s see the third and last identifier (the second novelty of ECMA 6 in terms of variable identifiers) that can be used for the declaration of variables.
The variables declared with const behave similarly to those declared with let, with the difference that the former can not be reassigned . This completely eliminates the possibility of overwriting the const variables. For example:
const PI = 3.141592653589793; PI = 3.14; // error PI = PI + 10; // error
Also the const variables are affected by the block scope, indentically to the let. The following snippet is perfectly legal:
var x = 10; // who x è 10 { const x = 2; // who x è 2 } // who x è 10
Another peculiarity of the variables <code>const</code> lies in the fact that they must necessarily be assigned in the declaration phase. The following line of code is valid:
const PI = 3.14159265359;
While the following will produce a type error <code>SyntaxError</code>:
const PI; PI = 3.14159265359; // Uncaught SyntaxError: Missing initializer in const declaration
In this case the const variables may appear to be true constants , since they can not even be declared and assigned later (as a variable):
const i; // Uncaught SyntaxError: Missing initializer in const declaration
However, this feature has a slight exception, which concerns, in the case of non-primitive data types (ie arrays and objects) the values, properties and methods of the variables. If it is not possible to reassign the data type in a const variable, however, it is possible to reassign one of its elements:
// creating an object const car = {type:"Fiat", model:"500", color:"white"}; // legal: update properties car.color = "red"; // legal: update properties car.owner = "Johnson";
However, it is not possible to update the const variable by reassignment:
const car = {type:"Fiat", model:"500", color:"white"}; car = {type:"Volvo", model:"EX60", color:"red"}; // ERROR
This snippet generates a SyntaxError: <code>Uncaught SyntaxError: Identifier ‘car’ has already been declared</code>.
The exact same thing happens with arrays. You can change the values of a const array variable, but do not reassign it:
const cars = ["Saab", "Volvo", "BMW"]; // legal: property update cars[0] = "Toyota"; // legal: adding an item cars.push("Audi"); // illegal cars = ["Toyota",&amp;nbsp;"Volvo",&amp;nbsp;"Audi"];&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// ERROR
Conclusion
As we have seen, we have two new and powerful tools at our disposal, which allow us to write Javascript code in a more intuitive, clear and concise way. Unlike some developers who claim that let and const have to completely replace var, my opinion is that all three identifiers must be used in the correct situations, knowing perfectly their behaviors and their characteristics. The var identifier remains very important also for reasons of backward compatibility.