Why does this program print 3 and not 2? - javascript

I am currently learning JavaScript, and right now I am on a topic discussing the differences between let and var.
Can someone explain why this code prints 3 and not 2? How does i even reach the value of 3 when the loop should stop executing once i becomes 2?
var i;
function printNumTwo() {
return i;
}
for (i = 0; i < 3; i++) {
if(i === 2) {
printNumTwo();
}
}
print(printNumTwo()); // prints 3

You are not printing anything while i is 2, only after the loop is when you call print. The Loop stops when i becomes 3.
To have it print 2, you have to change the printNumTwo() function like so:
var i;
function printNumTwo() {
print(i);
}
for (i = 0; i < 3; i++) {
if(i === 2) {
printNumTwo();
}
}

it because you have this line
for (i = 0; i < 3; i++) {
which increment value of i, and i is global variable and when you call you printNumTwo i value reached to 3 because of loop increment i value

When you print(printNumTwo()) i is 3. Calling printNumTwo() in the if statement does nothing but returning i which is not used by anything.
So basically the for statement runs and finishes making i=3 and then i is used by your print method.

You have to change start loop with let keyword because var is a global variable and let is block scope variable. that's why getting the different value.
You can try this
var i;
function printNumTwo() {
return i;
}
for (let j = 0; j < 3; j++) {
i = j;
if(i === 2) {
printNumTwo();
}
}
cosole.log(printNumTwo());

Try to use break statement it "jumps out" of a loop and continues executing the code after the loop if the specified condition is true.
var i;
function printNumTwo() {
return i;
}
for (i = 0; i < 3; i++) {
if (i === 2) {
break;
printNumTwo();
}
}
document.write(printNumTwo()); // prints 2

Related

The numbers from 1 to 20 (do not use arrays)

I need to show in console the numbers from 1 to 20 without an array..that s what i did:
function oneToTwenty() {
for (i = 1; i <= 20; i++) {
print i;
}
}
console.log(i);
what is wrong?
The console.log(i); should be inside the for loop:
for (i = 1; i <= 20; i++) {
console.log(i);
}
there's no such thing as "print". use console.log instead of print.
You also have an extra closing "}", which doesn't make sense.
for (i = 1; i <= 20; i++) {
console.log(i);
}
You need to put your console.log inside the loop. Otherwise, you firstly do the looping and then try to log the non-existent i.
Also, note that you have to declare i, if you have not done it, using var or let.
for (let i = 1; i <= 20; i++) {
console.log(i);
}

Using const as loop variable in for loop

I understand the behavior of using var and let in for loop in typescript/javascript but can someone explain why and how a const variable as a loop variable behaves ?
for (const i = 0; i < 5; i++) {
setTimeout(function() {
console.log(i)
}, 100 * i);
}
From what i understand , when you declare a variable as const and initialize its value , the value cannot be changed
Yet you can see the value being changed in the console.log() .An error has to be thrown while compilation right ?What am i missing here ?
I have created 2 examples for this behavior .
Loop variable as a const
Const variable re assignment
Can someone help me understand this ?
It works in Stackblitz because it is running traspiled code:
AppComponent.prototype.test = function () {
var _loop_1 = function (i) {
setTimeout(function () {
console.log(i);
}, 100 * i);
};
for (var i = 0; i < 5; i++) {
_loop_1(i);
}
};
It won't work if you add a snippet here because it is not transpiled
for (const i = 0; i < 5; i++) {
setTimeout(function() {
console.log(i)
}, 100 * i);
}
Answering your question,
test(){
for(const i =0 ; i< 5; i++){
setTimeout(function(){
console.log(i)
},100*i);
}
}
This code essentially becomes,
test(){
// can be only initialized once
const i;
for(i = 0 ; i< 5; i++){
setTimeout(function(){
console.log(i)
},100*i);
}
}
Because every JavaScript variable is hoisted at the top of its scope, in this case the test() as its const variable that's why its hoisted in that block and not accessible outside of it.
To correct the piece of the code:
test(){
// can be only multiple times in that block
for(let i = 0 ; i< 5; i++){
setTimeout(function(){
console.log(i)
},100*i);
}
}
Which becomes,
test(){
let i;
// can be only multiple times in that block
for(i = 0 ; i< 5; i++){
setTimeout(function(){
console.log(i)
},100*i);
}
}
As both const and let have block scope and is hoisted at the top of the block its defined in, the only difference between const and let is variables declared const cannot be reinitialized.

Is this the right equivalent for my loop?

I wrote a simple javascript code. My for loop iterates a "let" declared variable, i between 0 and 2. A function gets declared within the loop only when i == 2. The function has to return the value of i variable. When I call this function from outside the loop, the function returns the value of i = 2 (which is natural for a block scope variable i. However, when I rewrite the loop code as its non-loop equivalent code-block, the function (still called from outside the block) returns the vale of i = 3. What is going on?
"use strict";
var printNumTwo;
for (let i = 0; i < 3; i++) {
if (i === 2) {
printNumTwo = function() {
return i;
};
}
}
console.log(printNumTwo()); //returns 2
// loop equivalent
{
let i = 0;
i = 1;
i = 2;
printNumTwo = function() {
return i;
}
i = 3;
}
console.log(printNumTwo()); // returns 3
Your example is bad because your loop is not counting after 2. So If your loop looks like i <= 3:
for (let i = 0; i <= 3; i++) {
if (i === 2) {
printNumTwo = function() {
return i;
};
}
}
You would get exactly same result as your non-loop example and that's because of closure in javascript but return breaks for loop. Your function is saving reference to that variable from outside scope.
It's because you're actually setting the function to return the value 3 because of the non-loop environment. You should change the loop a little, adding another variable, but first make your function look like this:
printNumTwo = function() {
return num;
}
And in your simulated loop:
i = 2;
num = i;
printNumTwo = function() {
return num;
}
i = 3;
In your non loop based code, printNumTwo is not executed at the same point of its declaration and so the value of i is updated before it is executed so the value 3 is returned.
{
let i = 0;
i = 1;
i = 2;
printNumTwo = function () {
return i;
}
i = 3;
}
console.log(printNumTwo());
but if you run the following code, it should print 2 since it is executed before value if i is set to 3
{
let i = 0;
i = 1;
i = 2;
printNumTwo = (function() {
console.log(i);
})()
i = 3;
}
Note: return in for loop breaks the further execution of the loop, so even if your first code had i <= 3 as its breaking condition, it will return 2.
for (let i = 0; i <= 3; i++) {
if (i === 2) {
printNumTwo = function() {
return i;
};
}
}
console.log(printNumTwo())
"use strict";
var printNumTwo;
for (let i = 0; i < 3; i++) {
printNumTwo = function (i) {
// when references 'i' in this function, 'i' goes to the global scope.
return i;
};
// set the value 3 for 'i' in the global scope
i = 3;
}
console.log(printNumTwo()); // return 3;
try this
"use strict";
var printNumTwo;
for (let i = 0; i < 3; i++) {
printNumTwo = function (i) {
return i;
}.bind(null, i); // you set the current value as parameter = 0
i = 3; // i = 3 and break loop
}
console.log(printNumTwo()); // return 0;
try this
"use strict";
var printNumTwo;
for (let i = 0; i < 3; i++) {
let i = 0;
i = 1;
i = 2;
printNumTwo = function (i) {
return i;
}.bind(null, i); // you set the current value as parameter = 2
i = 3; // i = 3 and break loop
}
console.log(printNumTwo()); // return 2;
I appreciate all the answers I got to my question. All pointing to the case of how a function, when called, handles the environments in which it was both called and created. I read this useful explanation in the book "Eloquent JavaScript" and think it would be good to share it,
"A good mental model is to think of function values as containing both the code in their body and the environment in which they are created. When called, the function body sees the environment in which it was created, not the environment in which it is called."
~ Eloquent_JavaScript/Closure

Why is this function creating an infinite looop?

The first function determines if a number is prime. The second function is supposed to create an array with all prime numbers up to and including the max value, but it gives me an infinite loop for some reason.
function isPrime(num) {
for (i = 2; i < num; i++) {
if (num % i === 0) {
return false
}
}
if (num <= 1) {
return false;
}
return true;
}
function primes(max) {
var all = [];
for (i = 2; i <= max; i++) {
if (isPrime(i)) {
all.push(i);
}
}
}
primes(17);
Your i variable is global, so both functions use the same i. This means the first function changes it while the second one is looping.
As the first function will have set i to num-1 when it finishes, and num was the value of i before executing it, it effectively decrements i with one. And so i will get the same value in the next iteration of the loop in the second function, never getting forward.
Solve this by putting the var keyword in both functions.
for(var i=2; // ...etc)
The variable i in your two loops are global variables and they overwrite each other so the first loop never ends.
In ur code problem is with the scope of variable i, In prime no calculation, u can check upto the sqrt of no, if no is not divisible by any no upto its sqrt, then it will a prime no, Try this:
function isPrime(num) {
let k = Math.sqrt(num);
for (let i = 2; i <= k; i++) {
if (num % i === 0) {
return false
}
}
return true;
}
function primes(max) {
let all = [];
for (let i = 2; i <= max; i++) {
if (isPrime(i)) {
all.push(i);
}
}
console.log(all)
}
primes(17);
primes(25);

Value gets overwritten because of access by reference

a = [];
for (var i = 0; i < 3; i++) {
a.push(function() {
console.log(i);
})
}
a[0]() // I want 0, but I get 3
I am trying to write a simple piece of code where I have an array of functions such that when I execute a function at a particular index, the index value should get printed.
However, the piece of code above shows the same result (3 in this case) for all index values. I understand that the value is pointing by reference and therefore points to the last value of i. Could someone point out how to do this in the right manner?
Wrap it around a function. Now each time the loop executes, the wrapper function has its own value of i.
a = [];
for (var i = 0; i < 3; i++) {
(function(i){
a.push(function() {
console.log(i);
})
})(i);
}
a[0]()
You can add a self executing function to act like a module. Doing this, the scope of the variable i is in that function.
a = [];
for (var i = 0; i < 3; i++) {
(function(i){
a.push(function() {
alert(i);
})
})(i);
}
a[0]()
Note: In this block (function(i){ ... })(i), i can have any name, there is no connection between i from loop and i from function, i.e. (function(r){ ... })(r).
Here is an alternate version to an anonymous function that gets created and executed all at once.
The issue that you are having is that when the function gets called, the loop has already been evaluated and the value of i has already reached the max value of 3. You need trap the current value of i while the loop is being evaluated.
var a = [];
for (var i = 0; i < 3; i++) {
var fn = function() {
console.log(arguments.callee.i);
}
fn.i = i; // Pass as 'i' parameter to 'fn'.
a.push(fn);
}
a[0](); // The value 0 will be printed, rather than 3.
There is more than one way to skin a cat. The code above is very similar to:
var a = [];
function fn(i) {
return function() {
console.log(i);
}
}
for (var i = 0; i < 3; i++) {
a.push(fn(i));
}
a[0](); // The value 0 will be printed, rather than 3.

Categories