1

I am learning about For Looops and I find that the following two pieces of code work just the same. Code 1:

for (let i=0 ; i<bobsFollowers.length; i++){
  for ( let j=0; j<tinasFollowers.length; j++){
    if (bobsFollowers[i] === tinasFollowers[j]){
      mutualFollowers.push(tinasFollowers[i]);
    }
  }
}

console.log(mutualFollowers);

Code 2

for (i=0 ; i<bobsFollowers.length; i++){
  for ( j=0; j<tinasFollowers.length; j++){
    if (bobsFollowers[i] === tinasFollowers[j]){
      mutualFollowers.push(tinasFollowers[i]);
    }
  }
}

console.log(mutualFollowers);
  • 4
    Yes you should include , otherwise `i` & `j` will be globally accessible and can be changed by other functions – brk Nov 17 '20 at 06:09
  • 2
    It's seen as a good development practice to avoid polluting the global environment. – Ouroborus Nov 17 '20 at 06:25

5 Answers5

4

You can globally access the variable if you do not include let keyword

for (let i = 0; i < 3; i++) {
  console.log(i);
}

for (j = 0; j < 3; j++) {
  console.log(j);
}

console.log('j ', j); // accesible
console.log('i ', i); // inaccesible
firatozcevahir
  • 892
  • 4
  • 13
2

Yes, if you do not specifically use the let keyword in a for, for...of or for...in loops etc, they will work the same as when you use the let keyword.

However, when you don't explicitly declare using let keyword, the variable will be declared as a var. let and const are block level variables, but you also need to understand that 'functions are not the only blocks, any { } is basically a block'. i.e. Once declared a 'var' will become a function scoped variable and in case it is not inside a function, and declared outside, then it becomes globally available, which is not such a good thing considering you might have multiple for loops using a variable named 'i' and if you don't use let, it will just keep incrementing the old 'i'. Please see the below two examples to understand what I mean by the above sentence:

const test = function(){
let let1 = 1;
var var1 = 2;
{
let let1 = 9; //This is a block scoped variable limited to this { } block 
var var1 = 3; //re-initialization still overrides the original var 1 variable's value because once declared, the var variable is function scoped

console.log(let1); //9 - Block Scoped
console.log(var1); //3 - Function Scoped
}
console.log(let1); //1 - Function Scoped 
console.log(var1); //3 - Still Function Scoped, always function scoped
}

test();

What I meant by globally incrementing value of 'i':

for(i=0; i< 2; i++){
console.log('first loop', i)
}

for(i;i< 5; i++){//I am not initializing i to 0, but I'm just trying to show that it is a global variable now.
console.log('second loop', i)
}

for(i; i< 7; i++){ //I am not initializing i to 0, but I'm just trying to show that it is a global variable now.
console.log('third loop', i)
}

Secondly, in ES5, Strict Mode was introduced, which basically is a way you can opt out of writing 'sloppy mode' JS code, and you can use it by specifying 'use strict'; globally or at a function level. And strict mode is used in most companies and developers in their professional code bases.

The point I want to convey with this is that 'Strict Mode' does not allow you to use for loops without declaring the variable, you have to explicitely specify the 'var' or 'let' keywords. Therefore it is always a good practice to declare your variables. You can read more about strict mode here: Strict Mode

Lastly, in the current post ES6 times, using the var keyword to declare variable is not considered as a good practice due to something called as Hoisting, which basically means that before the a var x; is declared, if you try to use it, you still can, however it's value will be 'undefined'. But in case of let you cannot use a variable before you declare it. You can read more about it Here : Hoisting

Also, in case of let if you try to access a variable before it's initialized, it throws you a Reference Error. This is because of a concept called as a 'Temporal Dead Zone'. You can read more about it here: TDZ

Link
  • 1,198
  • 4
  • 14
2

Yes, you have to. Or the old var As other responses mention you will populate this variable in a broader scope.

Imagine this situation, You need to create a function that print the first 10 numbers:

function printNumbers(){
    for (i=0; i<10; i++) {
        console.log(i)
    }
}

That's cool. Now you need to invoke this function 12 times, easy right?

function printNumbers(){
    for (i=0; i<10; i++) {
        console.log(i)
    }
}

for (i=0; i<12; i++) {
   printNumbers()
}

Well, if you execute this in your google chrome console (don't). You will fry your browsers. Since i will never reach 12 and you will be in an infinite loop. You can test this safely by changing 12 by 5, you will see that the function only runs 1 time and not 5.

So it is not for your code (only), it is for who is going to use your code in the future. You are leaving a potential big fail in your code. Imagine it is in a library.

You have a good explanation already in StackOverflow about scoping and let here: What's the difference between using "let" and "var"?

Also about scope in general here: What is the scope of variables in JavaScript?

Raúl Martín
  • 4,471
  • 3
  • 23
  • 42
1

'let' is all about lexical scope, by default variables and objects in javascript have a global scope. As other have pointed out, using var will make the scope of variable global so anything can access and modify it.

Another use case for let would be in closures. This example is from CS50's react native lecture 0 & 1.

Here makeFunctionArray returns an array of functions which print the value of i.

function makeFunctionArray() {
  const array = [];
  
  for(var i=0; i<5; i++) {
    array.push(function () { console.log(i) });
  }

  return array;
}

const functionArray = makeFunctionArray();
functionArray[0]();

Now, what do you expect functionArray[0]() to print? 0, right? because we're invoking the function at index zero and it should console log 0. But it doesn't print 0, instead it prints 5.

This is because 'i' has a global scope and will have a value of 5 when loop terminates. the function(closure) we're returning from the makeArray function will still have access to 'i' and the value 5 gets wrapped up in it while being returned. so every functionArray[index]() will print 5.

This can be avoided with 'let' if 'i' is a let, its scope will only be the 'for' loop.

At the end of this lecture, this scenario is introduced and answered in next lecture

Akash Sarode
  • 387
  • 2
  • 13
0

The scope of let is restricted to that block alone. but if you do not specify let keyword it is scoped to the global environment(the global scope of the browser is window object)

{
   let a = 1;
   b = 2;
}

console.log(a) //error
console.log(b) //2