FAQ: Loops - The For Loop

Hi everone,
**Could some shed some light on why the following code

const nums = [1, 2, 3];
for (let i = nums.length - 1; i >= 0; i–) {
console.log(nums[i]);
}
console.log(‘Time is up!’);

would prints this?
3
2
1
Time is up!

When my expectation is the following (due to num.length minus 1 which is 2, so it should count down from 2, but it is starting the count from 3 and ignoring the minus 1)
2
1
Time is up!

There’s the why… nums[2] is 3

I’m revisiting this topic, and I realized that I use var an awful (or maybe not-so-awful :rofl:) lot in my code… @stetim94 I’m wondering if what you mean by "and not even var" is that using var instead of let is a bad practice?

Not to butt in, but time’s a-wasting. There is no connection to bad practice. var is still valid since JS is backward compatible. Only thing it lacks is block scope. It retains function scope, though, which was the intention all along, pre-ES2015.

Variables that are defined without declaration are automatically var in global scope with bindings to the ‘window’ object, if I’m not mistaken.

function foo() {
   a = 42
}
console.log(a)

In a function, using var or let is moot at top scope. They are both accessible from any inner scope.

The paradigm has shifted somewhat, but that only points to a slight change in thinking. Once we think in terms of leakage and go backwards, it all falls into place in our common practice. Even in ES5 days we still had the ‘no polluting global scope’ proviso. All block scope has brought to the table is refinement of where variables get garbage collected. Once any block is exited it gives up the memory its let or const variables used since their references no longer exist.

All along, var declared variables lost their references when a function was exited. This keyword has the same purpose and value it always had. If it slips in now and then, it’s not a sin if it is in function scope. If we use it in a block, then it is still okay, but we know the variable will leak out of the block. This could be good thing, when we think about it. Remember, inside a function we have a general rule of always declaring local variables. So any new variable should be declared. Maybe we have a use for that variable at the end of loop or switch, for instance. More proof of validity and usefulness.

2 Likes

The other day a topic surfaced asking what was the difference, to which I postulated it is one of binding. Let’s see if this plays out.

 > var a = 42
=> undefined
 > a
=> 42
 > window.a
=> 42
 > let b = 6
=> undefined
 > let c = 7
=> undefined
 > window.b
=> undefined
 > window.c
=> undefined   

That tells us that let in global scope has no binding to window. Something that may be worth knowing somewhere down the road.

Let’s see how that applies to undeclared local variables of a function.

function foo() {
    z = 42
}
foo()
console.log(window.z)    //  42

This supports our earlier assumption that undeclared variables are var declared in global scope since they have window binding. Also something to know for the future, for whatever purpose it serves.

3 Likes

2 posts were split to a new topic: Why does ‘for’ use ‘;’ between parameters?

Hi guys,

When I run console.log(userChoice(‘A’)) on the last line of code it runs the correct loop but then ends with the word undefined. How do I remove the word undefined and just log the results from the loop to the console?

Thanks everyone!

countToThree = () => { for (let i = 1; i <= 3; i++) { console.log(i) } }; runAway = () => { return 'Game Over.' }; userChoice = (choice) => { if (choice === 'A') { return countToThree() } else if (choice === 'B') { return runAway() } else { return 'Input not valid. Select A or B.' } }; console.log(userChoice('A'))

your countToThree function doesn’t return anything. So when we choice A, we get undefined

Either: make your countToThree return something, or you need to do a check that the returned result is not undefined:

const result = userChoice('A')
if (result)
{
   console.log(result);
}

Why does the example shown:
for (let counter = 0; counter < 4; counter++) {
console.log(counter);
}

print: 0, 1, 2, 3
since counter is being updated before it can print shouldn’t it start by printing 1?

1 Like

counter is not being updated before it can print. The final parameter only comes into effect at the end of the loop body, followed by the conditional test. These are parameters, not inline code.

But that is a great question. Why the “stopping condition” works in the first iteration, but the counter does not?

for (let counter = 4; counter < 4; counter++) {
console.log(counter);
}

That should print 4… but it does not.

The loop is never entered since the ‘run state condition’ failed.

  • initialize
  • test against condition
  • if condition passes, enter loop body and execute code
  • increment counter

Exactly, that makes sense. But if the condition does not passes, then the variable still ha the same value, right?

If those are parameters, not line code, when I print the variable, it should print the last value. But it does not.

Yes, the variable still refers to the number, 4. The line in the loop does not execute so there is no logging. Try logging after the loop.

Sorry, but I get an error saying that “counter” is not defined. That’s because the variable counter is only in the scope of that funcion, right?

I believe we will have to just accept that… there is no really any rational behind it, I would say. It is what it is.

So what happens here:

for (let counter = 0; counter < 4; counter++) {
console.log(counter);
}

1.Set the variable to 0
2.Check the condition
3.If true, prints the variable
4. add one to the variable value

I tried this:

for (let counter = 3; counter >= 0; counter–){

console.log(‘blah’);

}
And it printed

blah
blah
blah
blah

So that is it. If the condition is true, it runs the function first.

Thank you @mtf for your patience and for answering so quickly. Really appreciate it.

1 Like

You discovered block scope, and the reason we cannot print counter after the loop. Remove let from the initialization to expose it to outer scope.

That is, the code block. The code is not a function. for is statement, as are the lines enclosed in its body.

1 Like
for (let trax = 5; trax === 11; trax++){
  console.log(trax);
}

for (let trax = 5; trax = 11; trax++){
  console.log(trax);
}

Why doesn’t these two work ?

The first loop evaluates false at its first iteration, given 5 does not equal 11.

the second loop, the assignment will simple result evaluate a positive integer as truthy

1 Like

A numerical for loop generally iterates over a sequence made from the values in an interval… The iteration variable takes on a new value from the sequence as long as the value falls within the interval.

The middle parameter is meant to be a conditional expression, not a statement (trax = 11 is a statement) which will result in an infinite loop. That would be bad for any program as the only way to stop it is to intervene with the task manager and kill the process. Definitely do not want that.

As to the interval, we can test if our current value falls within it by using an inequality expression.

x = 5; x <= 11; x++
       _______

The inequality reads, x less than or equal to 11 which qualifies all the integer values, `5, 6, 7, 8, 9, 10, and 11, after which the loop terminates.