DEV Community

loading...

The difference between var and let

hadarharush profile image HadarHarush ・4 min read

Var and let are two varible declaration types in javascript, that have lot of common behaviours. Though, there is some big differnces between this 2, and every javascript programmer needs to know them.

For understanding some of this differences, first we need to understand the difference between two javascript scopes : the Function scope, and the Blocked scope. Function scope is the area between the two curly braces that comes after the declaration:
function func1(){
//we are now inside the function scope...
}

Block scope is the area between two curly braces that not bind to a function. For example:
{let l1 = 'l1' //we just declared the varibale l1 inside a block scope}
but also in:

if(2 > 1){
  let l2 = 'l2'
  console.log(l2)
  //we declared the variable l2 inside block scoped 
}
Enter fullscreen mode Exit fullscreen mode

Both scope types have a lexical variables scope. it means that in both scopes, if we are declaring a variable inside of them, we will cannot be access this variables from an outer scope:

if(2 > 1){let l3 = 'l3'}
 console.log(l3) //Error, because we not recognize l3 outside of its scope
Enter fullscreen mode Exit fullscreen mode

and also:

function func2(){let l4 = 'l4'}
func2()
console.log(l4) //Error, because we not recognize l4 outside of its scope
Enter fullscreen mode Exit fullscreen mode

But, there is a little problem we didnt mention: In a Block scope, a var declaration will leak out!
Not like const or let, var that declares inside a block scope will leak out to the outer scope. For example:

if(2 > 1){
  let l5 = 'l5'
  var v5 = 'v5'
}
console.log(l5) //Error, because we not recognize l5 outside of its scope
console.log(v5) //outputs 'v5'
Enter fullscreen mode Exit fullscreen mode

So what happened in the code above?
We declared the variable l5 with the keyword let, and its remained inside is block scope.
We declared the variable v5 with the keyword var, and as we say before, it leaked out to the outer scope, (this case: the global scope).

Notice that this behaviour occurs only inside a Block scope.
in Function scope, the rules are still clear, and all the 3 keywords: var, let, and const, will remain in the Function scope and wont leak out:

function func3(){
  var v6 = 'v6'
  let l6 = 'l6' 
}
func3()
console.log(v6) //Error, because we not recognize v6 outside of its scope
console.log(l6) //Error, because we not recognize l6 outside of its scope
Enter fullscreen mode Exit fullscreen mode

Another difference between var and let is the re-declaration.
in var, a declaration of variable with a name that is taken by another variable, will just apply the new value to the variable:

var v7 = 'v7'
var v7 = 'javascript'
console.log(v7) //outputs 'javascript'
Enter fullscreen mode Exit fullscreen mode

in let, it wont happend, and this operation will cause an Error:

let l7 = 'l7'
let l7 = 'l8' //Error, the variable-name "l7" is already taken
Enter fullscreen mode Exit fullscreen mode

Now when we know thes 2 diffrences we can discuss a famous Error that caused by the var keyword, and how we can fix it easily with the let keyword:

for (var i = 0; i < 3; i++) {
  setTimeout(() => {
    console.log(i)
  }, 1000)
}
Enter fullscreen mode Exit fullscreen mode

The output we except (after a second) is "0 1 2", but actually, the output we will get is "3 3 3" Why is that?

When we insert the first statement of the for loop (var i = 0),
the code that actually will be in the block of code inside will be something like this:

{
  var i = 0
  setTimeout(() => {
    console.log(i)
  }, 1000)
}
Enter fullscreen mode Exit fullscreen mode

Moreover, if you noticed, this code-block is actually a Block scope, and its means that all the rules that we mentioned earlier are applies to here too.

Therefore, in the first iteration, when the javascript engine sees a var declaration inside of Block scope, he leaks its out to the outer scope (in this case: the gloabl scope), so now, the variable, i, will be placed in the global scope!

in the second iteration, when javascript engine will read the
var i = 1 inside a Block scope, he will want to put it in the global scope again, but this time, we already got a variable named "i" in the global scope. So, as we mention above, in this case of var, "in var, a declaration of variable with a name that is taken by another variable, will just apply the new value to the variable". So now, the global variable i is equal to 1, and the same thing will happend in the next iteration and it will be with the new value 2. at the end of the last iteration, the for loop will then increase this value by 1 again (to 3), and then the term i < 3 will be false, and the iteration stream will stop.

for (var i = 0; i < 3; i++) {
  setTimeout(() => {
    console.log(i)
  }, 1000)
}
Enter fullscreen mode Exit fullscreen mode

Now, lets talk about the process that will happen second after that. The first timeout will exceed, and the order console.log(i) will be executed. But, now the i variable is equal to 3 so the output of this execution will be 3. The same thing will happen in the second timeout that we created in the for loop, and also to the third, which, for summery, will output "3 3 3"

So how we can fix that with let? Let's see.

for (let i = 0; i < 3; i++) {
  setTimeout(() => {
    console.log(i)
  }, 1000)
}
Enter fullscreen mode Exit fullscreen mode

Now, the only change is that the declaration type is let, and not var. So how it works?

Now, every iteration code block looks like this:

{
  let i = 0
  setTimeout(() => {
    console.log(i)
  }, 1000)
}
Enter fullscreen mode Exit fullscreen mode

In the first iteration, the variable i is declared inside the Block scope, and as we study, it will remain there and not leek to the global scope. This occurence will apply also to the secind and third iterations. But there is an inportant fact we need to notice: also the whole three variables i are in Block scopes that have a common "level", each block scope is unique, and has its own environment varibales. Therefore, the i that exist in the Block scope of the first iteration, isnt the same variable that the exist in the second iteration Block scope, etc.

its means, that when the console.log(i) execution will occur, each console.log will pring the i that he knows in his variable environment and the output will be "1 2 3"

Discussion (0)

pic
Editor guide