; in Javascript Loops - What affect does it have and why?

I’m new to Javascript and I’m very confused about the use of “;” in loops. I’ve tried to find the answer to this question and looked at it from every angle my limited knowledge will allow me, to but to no avail. The problem is that in all my learning and challenges so far, I’ve only ever seen loops use {} in the syntax.

I came across this while playing around with loops in a challenge. Below is the code I am working with and the console log results depend on whether I include the ; after the loop or not:

const    var = ["a", "b", "c", "d", "e"];
for (n  in  var) ;      *//position 1*
	console.log( var[n]) ;
        console.log(" n) ;  

Case 1: If I include it after the loop (position 1), I get a single result for each console.log:

  • e
  • 4

Case 2: If I don’t include it after the loop, I get all results for the first console log (a to e), but only the last result for the the second console log (index 4):

  • a
  • b
  • c
  • d
  • e
  • 4

I have two queries on this:
1. I’d like to understand what is happening when I include or don’t include ; after the loop.
2. In Case 2, I don’t know why the first console log lists all of the results, while the second one only lists the last one . I would really like to understand what is happening in the background with this and why both sets or results are not shown in their entirety.

You are getting strange looking results because you are not using {}. If you have multiple lines of code in your loop, you must use {}. JavaScript is not like Python - white space is not syntactically important. The only way for a loop to know what is contained inside of it is to 1) look for the next end of line character (; which is inserted automatically by JavaScript if you don’t put it in) or 2) to look for an enclosing {}. In case 1, only one line of code will be executed by the loop. In case 2, everything in the enclosing {} will be executed. Same thing goes for if statements.

1 Like

Thanks for the quick response JeremyLT.

I appreciate the use of {} and had mentioned that I’d only ever seen loops with them until this challenge. My query is I’d like to understand what is happening in the background, as in how the code is interpreted, when I don’t use {}, but do or don’t use ; after the loop.

Or… Is it the case that this never actually occurs in development (the person who wrote the challenge maybe got it wrong) and I shouldn’t worry about it?

That’s what I was talking about above. Let me make my comments a bit clearer.

Consider this loop.

for (let i = 0; i < 5; i++)
    console.log(i);

This works fine because we are only executing one line. If there are not enclosing {}, then the loop will only run the ‘next line’ of code. Since whitespace is not syntatically meaningful to JavaScript (and C, C++, CUDA, ect), what this means is that the loop will execute the code between the end of the loop head and the next ;.

Now consider this example.

for (let i = 0; i < 5; i++)
    console.log(i)

In this case there is no ;, so how does the loop know where to stop? Well, JavaScript will add a ; before each new line automagically for you. So actually, this code is converted to the previous example before it is run.

Now we can screw with this. Consider this example

for (let i = 0; i < 5; i++) ;
    console.log(i)

Since I used let, we get a good error message that actually explains what’s going on here.

ReferenceError: i is not defined
    at /home/runner/IncompatibleBitterNlp/index.js:2:17
    at Script.runInContext (vm.js:131:20)
    at Object.<anonymous> (/run_dir/interp.js:156:20)
    at Module._compile (internal/modules/cjs/loader.js:1133:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1153:10)
    at Module.load (internal/modules/cjs/loader.js:977:32)
    at Function.Module._load (internal/modules/cjs/loader.js:877:14)
    at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:74:12)

Because we did not use {} and we added that extra ;, the console.log() is now outside of the scope of the loop. But i is only in scope for the loop since I used let instead of var. So when I hit that line, the code throws this error because I am trying to access the variable outside of the scope of the loop.

We can make the same changes to your loop to show what’s going on.

As is:

const arr = ["a", "b", "c", "d", "e"]; // You shouldn't name a variable after a keyword. I changed var -> arr
for (let i = 0; i < arr.length; i++);
    console.log(arr[i]) ;
    console.log(i);

shows this error

ReferenceError: i is not defined
    at /home/runner/IncompatibleBitterNlp/index.js:3:18
    at Script.runInContext (vm.js:131:20)
    at Object.<anonymous> (/run_dir/interp.js:156:20)
    at Module._compile (internal/modules/cjs/loader.js:1133:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1153:10)
    at Module.load (internal/modules/cjs/loader.js:977:32)
    at Function.Module._load (internal/modules/cjs/loader.js:877:14)
    at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:74:12)

Removing the extra ;:

const arr = ["a", "b", "c", "d", "e"]; 
for (let i = 0; i < arr.length; i++) 
    console.log(arr[i]);
    console.log(i);

shows this error

a
b
c
d
e
ReferenceError: i is not defined
    at /home/runner/IncompatibleBitterNlp/index.js:4:15
    at Script.runInContext (vm.js:131:20)
    at Object.<anonymous> (/run_dir/interp.js:156:20)
    at Module._compile (internal/modules/cjs/loader.js:1133:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1153:10)
    at Module.load (internal/modules/cjs/loader.js:977:32)
    at Function.Module._load (internal/modules/cjs/loader.js:877:14)
    at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:74:12)

Using braces:

const arr = ["a", "b", "c", "d", "e"];
for (let i = 0; i < arr.length; i++) {
    console.log(arr[i]) ;
    console.log(i);
}

shows this output

a
0
b
1
c
2
d
3
e
4

Note: You cannot use var as a variable name in JavaScript it is a “reserved word”. I have changed it to arr in the below examples.

The reason that you aren’t seeing what @JeremyLT is describing, is because you are not using const, let, or var to declare your variable n. If you run in strict mode (always recommended) you won’t be able to do that. Otherwise, JavaScript will declare n for you in the GLOBAL scope.

See here:
https://repl.it/repls/EffectiveIllegalLocatorprogram

If we declare n correctly, you will get an error because it is outside of the loop and therefor n is not defined.
See here:
https://repl.it/repls/CaringLoathsomeScripts

Neither of your console.log lines are inside the loop, because you have a semicolon after for (n in arr)

When we remove the first semicolon, the first console.log is the body of the loop. The second one is outside the loop (because you aren’t using curly brackets).
See here:
https://repl.it/repls/ImaginaryForcefulExecutable

When we add brackets, we get the result that you probably wanted.
See here:
https://repl.it/repls/BusyJubilantDeskscan

This makes it much clearer! Thank you, I really appreciate your time on this.

1 Like

Thanks ArielLeslie, I hadn’t considered “scope” affect on this.

1 Like