What's difference between returning out of curly-braces and in of it within for loops?
I have this code making 'factorial' in for loops code quiz of Udacity and it is marked as 'right answer' only if 'console.log(solution) is out of for loop braces. Why can I put it inside for loop? Can't really understand why is that.
var solution = 12;
for (var i = 1; i < 12; i++) {
solution = solution * i;
console.log(solution); /* Why inside of the loop like this is
wrong? */
}
var solution = 12;
for (var i = 1; i < 12; i++) {
solution = solution * i; // 12 = 1 * 2 * 3 * .... 12
}
console.log(solution); /* only it works when it's out of the loop
like this one but why???? */
The difference is that inside the loop you are outputting the contents, or the current state of solution every time the loop repeats (in this case 11 times), when it's outside the loop body, you are only outputting the final state of the variable, or just 1 time.
Related
I have four different button effects where each effect are declared in a variable.
Therefore, I bring all of these four variables and place them within an array called arr in which is used in the clickByItself() function using Math.floor(Math.random()) methods.
Without the for loop, the code clicks by itself randomly in one of the four buttons every time I reload the page.
function clickByItself() {
let random = Math.floor(Math.random() * arr.length);
$(arr[random]).click();
}
However, using the for loop I am not being able to make these clicks one-by-one within the maximum of 10 times.
var blueButtonEffect = code effect here;
var redButtonEffect = code effect here;
var greenButtonEffect = code effect here;
var yellowButtonEffect = code effect here;
var arr = [blueButtonEffect, redButtonEffect, greenButtonEffect, yellowButtonEffect];
//will click on buttons randomly
function clickByItself() {
let random = Math.floor(Math.random() * arr.length)
var i;
for (i = 0; i < 10; i++) {
$(arr[random]).click();
setTimeout(clickByItself(), 1000);
}
}
The final output with the current code above is the four buttons being clicked at the same time, not one-by-one.
So, how can I have this function to press a random button by 10 times one-by-one with one second of interval from each click?
To fix your code you need:
A base case for your recursion
Pass a function reference to setTimeout. Currently, you are executing clickByItself and passing its return value (which is undefined) to setTimeout.
Do not use setTimeout in a loop without increasing the time by a factor of i, as the for loop will queue all the function calls at the same time
Alternatively, you can use a "times" argument to avoid looping
You could try something like
function clickByItself(times = 0) {
let random = Math.floor(Math.random() * arr.length)
$(arr[random]).click();
if (++times < 10) {
setTimeout(function(){clickByItself(times);}, 1000);
}
}
An example with console logs
https://jsfiddle.net/pfsrLwh3/
The problem is that the for loop calls the setTimeout 10 times very quickly. If you want to wait until the previous function call finishes prior to calling the next, then you should use recursion or just use a setInterval.
Recursion:
function clickByItself(numIterations) {
let random = Math.floor(Math.random() * arr.length)
let i;
$(arr[random]).click();
if( numIterations < 10 ){
setTimeout(() => {
clickByItself(numIterations += 1)
}, 1000)
}
}
clickByItself(0);
With setInterval
let numIterations = 0;
function clickByItself() {
let random = Math.floor(Math.random() * arr.length);
let i;
$(arr[random]).click();
numIterations += 1;
if( numIterations > 10) {
clearInterval(loop)
}
}
let loop = setInterval(test2, 1000);
Are you saying this is working for only 4 times but I think your above code will run in an infinite loop as you are calling clickByItself() again in the for loop.
If you want press a random button by 10 times one-by-one with one second of interval from each click then replace the for loop with
for (i = 0; i < 10; i++) {
setTimeout($(arr[random]).click(), 1000);
}
I’m trying to use an increment loop but I want it to increment at the end of the loop. Sadly, whenever I simply put the i++ at the end of the loop it doesn’t behave like I’d expect or want it to. Anyone mind showing me the proper way of doing it?
The referred increment loop:
for (i = 1; i < 15; i++) {
// do somthing here
}
Here is the loop I’m working with:
for (i = 1; i < 15; i++) {
for (x = 1; x < 15; x++) {
var take = document.getElementById("row" + i + "sm" + x);
Tesseract.recognize(take)
.then(function(result) {
console.log(result.text);
// rows[i][x] = result.text;
})
}
}
What I’d like it to do:
for (i = 1; i < 15) {
for (x = 1; x < 15) {
var take = document.getElementById("row" + i + "sm" + x);
Tesseract.recognize(take)
.then(function(result) {
console.log(result.text);
//rows[i][x] = result.text;
x += 1;
})
i += 1;
}
}
I am using the for loop because I need to iterate over something one by one. How do I properly increment i at the end of the loop?
Here is a video explaining my problem with context and explanation why it is not an ASYNC problem. Sorry if it is hard to follow, ill update it with audio soon so I can explain it propperly.
https://drive.google.com/file/d/1n1ZwNJif5Lb5zfLb2GPpBemObwpOqNf7/view
The problem is that the second one doesnt wait until first one is complete.
You can try with recursion inside then. There maybe some mistake with i,x but you get the point.
You execute first with i=1 and x=1, after the operation is done (then) you call the next until all elements are executed.
function execItem(i, x) {
var take = document.getElementById("row" + i + "sm" + x);
Tesseract.recognize(take)
.then(function(result){
rows[i][x] = result.text;
if (i < 15 && x < 15) {
if (i > 15) {
x += 1
i = 1
} else {
i += 1
}
execItem(i, x)
}
})
}
execItem(1, 1)
As a comment suggests this actually seems likely to be a problem with an asynchronous call (Tesseract...then) inside a loop. By the time the function inside then is called, your values of x and i have already moved on, so you don't get the result you expect.
One way around this would be to use a 'closure' - making a function that creates another function based on the value of i and x.
function getDisplayFunc(row, col) {
function displayRecognisedText(result) {
console.log(row, col, result.text);
//rows[row][col] = result.text;
}
return displayRecognisedText;
}
for (i = 1; i < 15; i++) {
for (x = 1; x < 15; x++) {
var take = document.getElementById("row" + i + "sm" + x);
Tesseract.recognize(take).then(getDisplayFunc(i, x));
}
}
I guess #Mike spot the error on: your code is asynchronous. What does it mean?
So, let's suppose you have this loop:
for (i = 0; i < 10; i++) {
console.log(i);
}
It will print this, right?
0
1
2
3
4
5
6
7
8
9
However, you do not print your value inside the loop directly, but as a follow-up operation to a promise. This makes this code asynchronous. It means that it does not have to execute at the exact moment you call it. I do not have Tesseract here so I will make my loop asynchronous using another very old trick, setTimeout():
for (i = 0; i < 10; i++) {
setTimeout(function() {
console.log(i);
}, 0);
}
If I run it, I get this:
10
10
10
10
10
10
10
10
10
10
What happens is, when I pass the operation we want to do (in this case, printing the i value) to an asynchronous function (recognize().then() in your case, setTimeout() in my case) through a callback (function() {console.log(i);} in my example) the asynchronous function "schedules" the operation to execute as soon as possible, but this "soon" is not faster than the loop. So, the loop finishes executing but our callback is not called, not even once! Since you are not declaring i with let, it is a global variable, so there exists only one i. And since the loop finished, the value of the i variable is 10 already.
It used to be a hard thing to solve, but with ES6 it is quite straightforward: declare i with let!
for (let i = 0; i < 10; i++) {
setTimeout(function() {
console.log(i);
}, 0);
}
The let-ed variable has a new binding at each iteration of the loop, so in practice you have 10 variables called i. The closure of your function will have access only to the one with the right value!
Maybe you should try to use while loop.
Like this:
while i < 15:
//do something
i += 1
For two variables: x, i with embeding:
while x < 15:
//do something
while i < 15:
//do something2
i += 1
x += 1
Hope I understand the problem correctly.
So I'm trying to make this coin flip but it keeps flipping forever... when I want it to stop after 10 times. I also need a counter variable that tells me how many times it is flipped.
var coin = randomNumber (0,1);
write (coin);
while (coin < 10) {
coin = randomNumber (0,1);
write (coin);
}
The easiest way is to just use a for loop.
for (var i = 0; i < 10; i++) {
var coin = randomNumber (0, 1);
write (coin);
}
See this for more information: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Loops_and_iteration
If you want to stick to the while loop:
var timesFlipped = 0;
while (timesFlipped < 10) {
var coin = randomNumber (0, 1);
write (coin);
timesFlipped = timesFlipped + 1; // alternatively: timesFlipped++;
}
You haven't shown us your randomNumber function, but it's likely that it only produces numbers that are less than 10. Since your while loop says to keep going as long as coin is less than 10, the loop goes forever.
while loops are notorious for resulting in infinite loops. I personally never use them. Since you know how many times you need to loop, a counting loop is the correct choice.
Here's what you need:
// Write the function that gets random number and report the results a certain number of times:
function coinToss(numTimes) {
// Instead of a while loop, use a counting loop that will
// have a definite end point
for(var i = 0; i < numTimes; i++){
// Get a random number from 0 to 1
var coin = Math.floor(Math.random() * 10);
// Test to see if it is even or odd by checking to see if
// it is divisible by 2 with no remainder.
var even = (coin % 2 === 0);
// Report the results
console.log("The coin was " + (even ? "heads " : " tails"));
}
}
// Now, call the function and tell it how many times to loop
coinToss(10);
This question already has answers here:
JavaScript closure inside loops – simple practical example
(44 answers)
Closed 5 years ago.
The following code works great. It pushes 10 unnamed functions into an array and then successfully executes the 7th item in the array.
var storeStuff = [];
for (let i = 0; i < 10; i++) {
storeStuff.push(function() {
console.log(i * i);
});
}
storeStuff[6]();
However the test function above is tiny. If I had a large function with many lines of code I'd likely want to declare it outside of the push.
For example what if I wanted to push a previously defined function and later invoke it like the example below?
var storeStuff = [];
function externalFunction(temp) {
console.log(temp * temp)
}
for (let i = 0; i < 10; i++) {
storeStuff.push(externalFunction(i));
}
storeStuff[6]();
Unfortunately this doesn't work as written and everything I've tried crashed and burned. What am I getting wrong?
Use function declaration as below
var storeStuff = [];
externalFunction = function(temp) {
console.log(temp * temp)
}
for (let i = 0; i < 10; i++) {
storeStuff.push(externalFunction);
}
storeStuff[6](6);
I am learning javascript to enhance some of my daily work, and so I am learning the basics.
I am still pretty green with the syntax, but am picking up on the language pretty quickly.
What I am trying to understand is how i can create a terminating condition that is evaluating a function.
I know the coding is wrong here, which is what I am trying to fix - I attempted a bunch of different things, but I am having trouble evaluating the loop based on my product.
I tried using return to store the value each iteration, but every attempt resulted in the script flat out failing.
What I want the script to do is to stop the loop when my product reaches <=100.
The problem is, my research suggests that the loop criteria can ONLY be referencing the variable, i.
I'm stuck in terms of how to look at the resulting product as the terminating condition.
var one = 5;
var two = 10;
var end = 100;
function mult (one, two) {
var product = one * two;
document.writeln(product + "<br>");
}
for (var i = 1; i <= end; i++)
mult(i, two);
If you want your loop to terminate when the product is <= 100, use an if statement to decide whether you want to write a line.
I've changed some variable names to make it easier to understand.
/*var one = 5;*/ /*This is never being used*/
var ten = 10;
var end = 100;
function mult (a, b){
var product = a * b;
if (product <= 100){
document.writeln(product + "<br>");
}
}
for (var i = 1; i <= end; i++){
mult(i, ten);
}
"the loop criteria can ONLY be referencing the variable, i." that's false!
You can define multiple conditions in a for loop.
To access the 'product' variable after loop execution you can declare it in the outer scope of the mult() function (or you can rewrite the mult() function to returns the product variable).
Like this:
var two = 10;
var end = 100;
var someNumberGtThan100 = 100000;
var lastProduct = 0;
var product = 0;
function mult (one, two) {
lastProduct = product;
product = one * two;
document.writeln(product + "<br>");
}
for (var i = 1; i <= someNumberGtThan100 && product <= 100; i++) {
mult(i, two);
}
console.log(lastProduct); // 100
By using this condition you have to store the previous value in an auxiliary variable, because when 'product' reach the value of 100 the loop condition is still true, so the loop will be executed one time more.