I was trying to make a for loop that increments through the numbers 1 - 4 and print them, but when I printed the value of i after the loop, my code outputs 5.
for (i = 1; i < 5; i++) {
document.write(i + "<br>"); //Outputs numbers 1 - 4
}
document.write("New i: " + i); //Outputs 5
How is this possible if i can only increment up until its value is 4?
When you declare a variable in a loop statement, it stores the variable in the same scope as the loop. Loops increment (i++) at the end of the loop, then check the condition (i < 5) to see if they should repeat. After the loop, the variable i still exists. See the snippet below for a play-by play.
Also, you should use the var keyword when declaring i, otherwise, the variable is stored in the global scope (which is bad practice).
//variable i is captured here (with the var keyword)
for(var i = 1; i < 5; i++) {
//for the fourth iteration, i === 4
//so it prints 4.
document.write(i);
//i++ happens right now, so i now is 5.
//then the loop checks the condition to see if it
//should continue. i isn't less than 5, so the loop breaks.
}
//and the value of i is still 5. so this prints 5.
document.write('</br>' + i);
You could move the final-expression part into the condition part of the for statement, where the increment takes place only if the value is smaller than 4.
var i;
for (i = 0; i < 4 && ++i;) {
console.log(i); // 1 ... 4
}
console.log('last value', i); // 4
The test clause of i < 5 is evaluated at the beginning of each loop; if it is false, the loop exits (leaving the value at 5). The i++ part always happens at the end of an iteration, meaning that after the number 4 has been processed in the loop, it increments it to 5, then it loops to the top of the loop where it checks the condition again (i<5) which it fails, but the value of i is not reversed back to 4.
The condition of the loop block to be processed is i < 5, thus i must be less than 5 for the statements and expressions within it to be evaluated
You increment i by 1 with each pass
When i equals 4, you increment it by 1 again such that i will be equal to 5. i < 5 is no longer true, so within the loop block is not executed
Nothing turns i back one increment; so it retains it after the loop
You can apply unique ways, but generally the first and last example below is the common approach:
var log = console.log;
// Example 1: Decrease Loop Iterator After
for (var i = 1; i < 5; i++)
log(i);
log('New i:', --i); // 4
// Example 2: Count in conditional
var count = 0;
for (var i = 1; i < 5 && ++count; i++)
log(i);
log('New i:', count); // 4
// Example 3: Count in loop body
var count = 0;
for (var i = 1; i < 5 && ++count; i++)
log(i);
log('New i:', count); // 4
you have declared i as global variable.
That's how the for loop works.
for (initialization, condition, increment/decrement ) {
}
You have initialized with 1 and it satisfies the condition i<5 so it enters the loop and prints i. after then it performs the increment/decrement operation and increases the value by 1 in your case. So while i=4 and i<5 it enters the loop and prints 4, but after then it performs increment operation and increase the value of i to 5.
In the next step, as the condition i<5 is not satisfied , so it breaks the loop and go to the last statement, where you are printing i, that is 5.
Hope it is clear now.
var array = [1, 2, 3, 4];
array.forEach(function(value) {
document.write(value + "<br />");
});
document.write("Values processed: " + array.length);
No, I‘m not kidding. Use arrays whenever you can, they will spare you a lot of trouble. The side effect you‘re in fact asking for can cause hard-to-track bugs (i looks like being meant for the loop only, imagine tons of lines between the loop and the last document.write). And there‘s the off-by-one error problem with for loops.
You‘ll probably anyway end up with an array once your code starts doing meaningful stuff (you don‘t want to count up to 4, do you?). So do yourself a favor an embrace all those powerful Array methods.
please use count variable because i value increases after each statement execution. i.e after your loop is finished execution i will be always 5
var count=0;
for (i = 1; i <5; i++) {
document.write(i + "<br>"); //I increases after these statement execution so it will be 5 at last
count=count+1;
}
document.write("New i: " + count); //Outputs 5
Related
The condition in the loop specifies i<3. Shouldn't the loop stop at i = 2? if so, shouldn't outside loop be 2 not 3?
Thanks.
for (var i = 0; i < 3; i++){
console.log(i, " loop")
if(i%2===0){
console.log (i,'even numbers in loop ');
}
}
console.log(i, " outside loop")
That's the correct behaviour of loops.
The loop starts with i = 0, then i = 1, then i = 2, then i = 3. oops i is no more less than 3, break the loop. that's what's going on, so when you log the value of i you get 3 and not 2.
Loop: it breaks as soon as i < 3 is not verified, which means in the last iteration. More informations about iterations.
Scope: because i is declared using var, which attaches the variable to the global scope. Using var is highly discouraged, use let instead, which declares variables in block scope. More informations about var and let.
I wrote a this simple code in js.
var n=10;
for (i=1;i=n;i++){
console.log('avinsyh');
}
But the loop executes greater than 2000 and crashing the browser.Why this is happening so?
Note: If I Execute this:
var n=10;
for (i=1;i<n;i++){
console.log('avinsyh');
}
Then the javascritpt outputs the correct results
It's the assignment in the comparison part of the for loop, which makes an infinite loop. i becomes always n and evaluates to true.
for (i = 1; i = n; i++){
// ^^^^^
var n = 10,
i;
for (i = 1; i <= n; i++){
document.write('i: ' + i + '<br>');
}
in your first for loop , i=n will set i equal to the value of n and thus return a truthy value(as n is not 0) and you get a infinite loop.
In your for loop you are assinging the value i = n which is always true and hence results in infinite loop.
The condition expression is evaluated. If the value of condition is
true, the loop statements execute. If the value of condition is false,
the for loop terminates. If the condition expression is omitted
entirely, the condition is assumed to be true.
In your second case you are comparing the value of i on each iteration and hence you are getting the expected result.
The basic syntax of for loop is:
for ([initialExpression]; [condition]; [incrementExpression])
statement
So in your first case you are not providing the [condition] rather it is an assignment.
I'm a bit stumped by the exact order of execution of a particular for loop I'm playing with, in Codepen. Check out these two loops, which both do the same thing:
var a = ['orange','apple'];
for (var i=0; i<2;i++) {
alert(a[i]);
}
for (var j=0, fruit; fruit = a[j++];) {
alert(fruit);
}
You can see this in action here: http://codepen.io/nickbarry/pen/MYNzLP/
The first loop is the standard, vanilla way of writing a for loop. As expected, it alerts "orange", then "apple".
I wrote the second loop using a suggestion from MDN (search for "idiom", here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/A_re-introduction_to_JavaScript ).
It works, but I don't quite understand why. My understanding of for loops, which is obviously incorrect in some way (more than one way?) is that:
* The for loop evaluates the truthiness of the second expression before it runs the first time. So it seems that when the for loop is evaluating the truthiness of the second expression, it should increment j before setting the value of fruit. So the first time through the loop, fruit should equal "apple".
* And the loop should only run once, because after the first time through, when it's evaluating the second expression again to see if it's still true, it should once again increment j before it returns a value to fruit, and since there is no value at index position 2, it should return a falsy result, and exit the loop.
I don't understand what actually IS happening. Does the for loop run once before the second expression is evaluated? But that seems impossible, because if that happened, the alert would alert nothing the first time through, since fruit wouldn't yet have a value.
Also, the author of the MDN article seemed to like the second way of writing the loop - is there a reason that way is better? It uses fewer characters, which is good, I guess. Does skipping the third expression in the for loop save significant time? Or is it just a "it's cool because it's clever" sort of thing?
for (var j=0, fruit; fruit = a[j++];) {
alert(fruit);
}
In pseudocode is equal to:
initialize j = 0 and fruit = undefined
assign fruit = a[j] (j = 0, fruit = 'orange')
j = j + 1 (j = 1)
check fruit for being truthy (true)
alert(fruit) ('orange')
assign fruit = a[j] (j = 1, fruit = 'apple')
j = j + 1 (j = 2)
check fruit for being truthy (true)
alert(fruit) ('apple')
assign fruit = a[j] (j = 2, fruit = undefined)
j = j + 1 (j = 3)
check fruit for being truthy (false)
exit loop
Important note:
The postfix unary ++ operator works as:
We return the current value of the variable
We increment the value of the variable
Does skipping the third expression in the for loop save significant time?
It does not save anything at all
Also, the author of the MDN article seemed to like the second way of writing the loop - is there a reason that way is better?
It's not better in any way. Author just thinks it's cool and author likes to be cool (while they are not).
A for loop is really just a shorthand way of writing a while loop.
e.g. this loop
for(var i = 0, j = 10; i < 10; i++, j++) {
alert(i + ", " + j);
}
is just a shorter way of writing
var i = 0, j = 10;
while(i < 10) {
alert(i + ", " + j);
i++; j++;
}
So that mans this loop
for(var j=0, fruit; fruit = a[j++];) {
alert(fruit);
}
is the same as this
var j = 0, fruit;
while(fruit = a[j++]) {
alert(fruit);
}
You can follow through the order of execution of JavaScript's for loop using SlowmoJS: http://toolness.github.io/slowmo-js/
The homepage already has the for loop loaded into the console for demonstration purposes, but you evaluate the order of operation of any code, as you see fit.
var functions = [];
(function foo() {
for (var i=0; i<5; i++ ) {
var f = function() {
console.log(i);
}
functions.push(f);
}
for (var i=0; i<5; i++ ) {
f = new Function("console.log(i);");
functions.push(f);
}
})();
for (var i=0; i<10; i++ ) {
functions[i]();
}
the output is :
5
5
5
5
5
5
6
7
8
9
can anybody help me sort out the flow?
first of all you should know whenever you want to run this function:
Function("console.log(i);");
this would use the current context's i variable as its value. so you might want to do:
var functions = [];
(function foo() {
for (var i = 0; i < 5; i++) {
var f = function func() {
console.log(func._i);
};
f._i = i;
functions.push(f);
}
for (var i = 0; i < 5; i++) {
f = new Function("console.log(" + i + ");");
functions.push(f);
}
})();
for (var i = 0; i < 10; i++) {
functions[i]();
}
I changed it this way and my result is:
0, 1, 2, 3, 4, 5, 6, 7 ,8, 9
Why is that?
1- all of the functions in your first for loop use a single variable i, and as its last value is 5 then all would print 5.
2- the other ones which get created in your second for loop, whenever they get invoked they would use the i variable in their current context, and as far as they get invoked in your last for loop, they use the i variable in the loop, to make it clear. you can easily change your last for loop like this:
for (var j = 0; j < 10; j++) {
functions[j]();
}
and as there is no i variable in the context (I changed it to j), then your output would be:
5 5 5 5 5 undefined undefined undefined undefined undefined
undefined is there because function can not fin any i variable in the context.
It's actually printing out five 5's and then 5, 6, 7, 8, 9. The first five 5's are from var i in that for loop, the functions save a reference to that var i and access it when you run it, and since it equals 5 at the end of the for loop, they all return 5. The second set of numbers comes from the quoted function accessing i from the for loop there, ergo it printing out 5, 6, 7, 8, 9.
Lots of good answers here:
How do JavaScript closures work?
The first 'for' loop is generating 5 functions each of them creates a closure which captures the 'i' as 5 (last value of 5 for that loop after last increment) so they all render out 5 (it just shows in Chrome as the first 5 with 5 in a circle next to it meaning the same value was logged out 5 times)
The second 'for' loop generates functions that will use 'i' from the scope it executes from, in this case the scope is the 3rd 'for' loop...
Closure allow you to access the variable from parent scope, which sometime cause strange or wrong behavior, here in this scenario closure is causing the output: 5 5 5 5 5 0 1 2 3 4
I am trying this code with:
f = new Function("alert("+i+");");
In first loop:
for (var i = 0; i < 5; i++) {
var f = function func() {
console.log(func._i);
};
f._i = i;
functions.push(f);
}
you are referencing i of parent means loop variable, so five different functions are created all with the same copy of variable i, which is changing with iteration, at the end of loop where condition break is i=5 since all functions are referencing the same copy, so change to original copy will effect all. So each function now has the i=5
Now in second loop, you are appending it as a string, which doesn't refer to original copy but creating a new string for each iteration:
for (var i = 0; i < 5; i++) {
f = new Function("console.log("+i+");");
functions.push(f);
}
this create five different functions with each different string:
console.log("0");
console.log("1");
console.log("2");
console.log("3");
console.log("4");
Now calling each function created by loop1 functions[0] to functions[4] is referring the same copy of i will print 5 while second functions[5]to end has there own strings to print.
I have the following small code snippet with the following expected and real output. My question is quiet simple. Why is it printing it this sequence? and how to I print the expected output?
Gr,
expected result:
0
1
2
0
1
2
real result:
0
1
2
3
3
3
this is the code:
var functions = [];
for (var i=0; i<10; i++) {
console.log (i);
functions.push (function () {
console.log (i);
});
};
for (var j=0; j<functions.length; j++) {
functions[j] ();
};
The functions that you push into the array doesn't log the value of i as it was when the function was created, they log the value of i at the time that the function is called.
Once the first loop ends, the value of i is 10, therefore any of the functions called after that will log the value 10.
If you want to preserve the value of i at different states, you can use a closure to make a copy of the value:
for (var i=0; i<10; i++) {
console.log (i);
(function(){
var copy = i;
functions.push (function () {
console.log (copy);
});
})();
};
The local variable copy will get the value of i and retain the value. You can also pass the value as a parameter to the function:
for (var i=0; i<10; i++) {
console.log (i);
(function(copy){
functions.push (function () {
console.log (copy);
});
})(i);
};
The expected result should be:
1
2
...
10
10
10
... 7 more times
The reason for this is simple. The console.log(i) inside your loop is correctly printing the value of i at each iteration of the loop. When you create and push a function into the functions array, what you're doing is closing each of those functions over the same variable i. At the end of your loop, i no longer satisfies your loop condition, so i = 10 is true. As a result, since each of those functions is going to execute console.log(i), and they're each closed over the same i, which now has value 10, you should expect to see the value 10 printed 10 times.
To prevent this, you will want to make a function which returns a function rather than creating functions directly in a loop:
var functions = [], i, j;
function createEmitter(i) {
return function () {
console.log(i);
};
}
for (i = 0; i < 10; i++) {
console.log(i);
functions.push(createEmitter(i));
};
for (j = 0; j < functions.length; j++) {
functions[j]();
};
Now, each of those created functions is closed over its own private scope variable, which resolves the problem.
You should update your code example to be i < 3 so that your results and function match up.
The functions you push into the functions array are storing a reference to the variable i, which after executing the top loop, is 10. So when it executes, it will go get the variable i (which is 10) and print that 10 times.
Here's a good way to see this in action:
for (var i=0; i<10; i++) {
console.log (i);
};
console.log(i) //=> 10
When you are using a variable, remember that the variable can change, it's not frozen at it's current value. You are only holding on to a reference to something else.
To fix this problem, I would run this type of minor refactor on the code (because the other answers have already created an extra scope, figured I'd give you something different). Rather than storing 10 functions, just store the numbers and execute them with a single function. This is a more elegant way to write it anyway, and takes up less space. I'm sure this example was abstracted from whatever code was really giving you the problem, but the general pattern still applies.
numbers = [];
for (var i=0; i<10; i++) {
console.log (i);
numbers.push(i);
};
numbers.forEach(function(i){
console.log(i);
});