Can anyone explain the working of the following recursive function? - javascript

I want to know that the following code is return number from 10 to 1 but after doing that it calls itself again 10 times but not doing anything. I tried to understand the code step by step with the help of the debugger variable but was not able to.
let countDown = function f(fromNumber) {
console.log(fromNumber);
let nextNumber = fromNumber - 1;
if (nextNumber > 0) {
f(nextNumber);
}
}
let newYearCountDown = countDown;
countDown = null;
newYearCountDown(10);
For more reference, please visit Javascripttutorial to know more about the code.

Recursion is a process of calling itself. A function that calls itself is called a recursive function. In your example, your first function doesn't get completed, but it's if condition is what is being run. During the if condition, your function is more like put on hold as another call is made. Your first function waits for it to complete.
In this fashion, 10 function calls are made and all are waiting inside the if condition. After the last condition (nextNumber == 0) fails, the function returns back to the 9th function where the if condition was waiting. Similarly, all your functions will get completed one by one from 9 to 1.

Related

How does this interesting piece of JavaScript code work?

A friend of mine brought to my attention a piece of JavaScript code that gives you unrealistic time scores on the flashcard website Quizlet's match game. It somehow stops the game's timer at the user specified time.
document.getElementsByClassName("UIButton UIButton--hero")[0].click();
setTimeout(function(){for(var F = setTimeout(";"), i = 0; i < F; i++) clearTimeout(i)}, 5100); //Change 5100
Using it is simple, you get on the match game (for example https://quizlet.com/187478162/match) and you simply enter this code in the console in the inspect menu. You then need to complete the game but it doesn't matter how long you take.
I don't know JavaScript (I am very knowledgeable with Python) but I have figured out so far that the first line clicks the start button and the first setTimeout function waits until the specified time to execute the function inside of it. It is the function inside that confuses me. It seems to just create and clear a bunch of Timeouts. I have no Idea how this stops the game timer though.
If someone could explain how it works that would be very much appreciated
Ah, that's a very interesting piece of code, very clever. Here's what's happening.
The inner function basically has the following (expanded for readability):
var F = setTimeout(";")
for(i = 0; i < F; i++) clearTimeout(i)
setTimeout can accept functions or strings that get evaluated after a timeout. They're just passing in the no-op ';', and they're not even passing in a delay. What they care about is the timer-id "F". If you go to the dev-tools (on a non-busy page), and put setTimeout(';') in the console, you'll see that it'll first return the id 0, then 1, then 2, and so on. The ids counts up.
So, you can imagine this timeline:
Random background stuff happens
The webpage starts a timeout with setTimeout, that has, lets say, id 7.
More background stuff
This script executes. It creates a timeout, and gets back an id that's going to be bigger than any timeouts made in the past. Lets say that id is 9.
Now the script goes through all ids from 0 to 9, stopping any active timeouts by passing in the id to clearTimeout. This includes clearing the timeout for id 7.
Before I get to the answer part, you should know a couple of things about setTimeout( ):
The setTimeout( ) function, can accept a callback function as it's first parameter, or, it can also accept code in a 'string'.
Whenever the setTimeout( ) function is called, it returns a timeout id which can be used in order to pass into the clearTimeout( ) function when you want to clear a particular timeout.
Now, please run the below code snippet and see what happens:
a) In the very first setTimeout call, I'm passing a callback function, storing the returned id in the const variable 'id1'.
b) In the second setTimeout call, I'm passing a code string, storing the returned id in a const variable 'id2'.
const id1 = setTimeout(() => console.log('setTimeout with callback fn'), 1000, '_');
const id2 = setTimeout('console.log("setTimeout with code string")', 2000);
console.log('id from 1st setTimeout( ) is :', id1);
console.log('id from 2nd setTimeout( ) is :', id2);
Both the setTimeout calls work without an issue, but the more interesting thing is when you look at the 'id' values for both function, for the first call the id is '1', for the second call the id is '2'.
This means two things: One these IDs are unique and secondly, these IDs are in the same ID pool, think of it like an ID list or an array where for each setTimeout call, a new ID is created by incrementing over the last existing setTimeout ID from the ID Pool.
Now, let's look at the code in question:
In the first line of code, the getElementsByClassName returns a nodelist of all the elements with the class passed in, and with the click( ), you are just simulating a buttonclick for the 0th element from the nodelist that is returned. You can use other functions like querySelector('UIButton UIButton--hero') or querySelecorAll('UIButton UIButton--hero') in this case and it will not make a difference in the way this works.
document.getElementsByClassName("UIButton UIButton--hero")[0].click();
Now, when we look at the below setTimeout( ) function calls with the knowledge we have about how the setTimeout function and setTimeout IDs work, it will be way easier to understand how it stops the actual timer:
setTimeout(function () {
for (var F = setTimeout("console.log(';')"), i = 0; i < F; i++)
clearTimeout(i);
}, 5100); //Change 5100
We are making an outer setTimeout call which takes in a callback function, and the timer for this setTimeout is set to '5100' milliseconds, which is basically a 5 second timer.
Looking at the callback function itself:
function () {
for (var F = setTimeout("console.log(';')"), i = 0; i < F; i++)
clearTimeout(i);
}
This callback function, runs a for loop, in the initialization block of this for loop, two variables are initialized, 'F' and 'i', value of 'F' is the ID returned by the current setTimeout( ) function, 'i' is set to 0.
Now from what we know from the code snippet I posted above is that the ID pool for all the IDs is the same, which means the ID 'F' is definitely going to be greater the setTimeout ID of the original timer that is present on the webpage.
Answer & Conclusion:
Now the loop itself iterates basing on the value of 'i', as long as it is less than 'F', and it clears the interval using clearInterval(i) for each value of i from 0 to F, which means it stops all timers on the page from ID = 0 to ID = 'F'.
And that is the reason this code can be used in order to exploit the website and stop it's timer so users can cheat and complete the quiz. Please let me know if you have any further queries.

For Loop Iteration Happening all at Once Rather than By Delay

For one of my elements on my page, I want the text to change every ten seconds, and for the class to be changed. Text changing is easy, as is class changing, but I'm having trouble with my for loop, and I feel like I'm missing something.
I want to have the for loop choose a random faction in an array, and then apply that to the element. For my testing, I've been using console.log rather than DOM manipulation.
First, I set up my array:
var factions = ["Enforcers", "Reapers", "Ular Boys", "Roaches"];
Then, I want a variable that is a number chosen at random in reference to this array:
var x = factions[Math.floor(Math.random()*factions.length)];
From that, I want the ability to run the Math.floor and Math.random functions elsewhere.
function reDefine() {
x = factions[Math.floor(Math.random()*factions.length)];
console.log(x);
}
Finally, I want the for loop to run 200 times (I've chosen 200 times because it's far and beyond the time the user will be staying on the site), so I told it to count to 200 (i = 0; i < 200). After that, I wanted each time it iterated, to wait 10s, so I have a Timeout function with a delay of 10000 (milliseconds). Then, the code to reDefine and then, in the case of testing, console.log the new definition of the x variable.
function reChange() {
for (var i = 0; i < 200; i++) {
setTimeout(function() {
reDefine();
console.log("Chosen faction is now: " + x);
}, 10000);
}
}
Instead of counting to 1 (the first iteration), waiting 10000, and then redefining x, it redefines x two hundred times, then logs them all.
Is there something I'm specifically doing wrong here, perhaps with the Timeout function?
Is there something I'm specifically doing wrong here, perhaps with the Timeout function?
Yes! You're scheduling a bunch of deferred callbacks, but not actually waiting until one has finished to schedule the next.
You can fix that with something as simple as:
function reChange(currentIndex) {
setTimeout(function() {
reDefine();
console.log("Chosen faction is now: " + factions[currentIndex]);
// If we haven't gotten to the end of the list, queue up another one
var nextIndex = ++currentIndex;
if (nextIndex < factions.length) {
// Enqueue the next faction
reChange(nextIndex);
}
}, 10000);
}
Make sure to note that the function without the timeout has closure over the value of currentIndex for each call of reChange. That is, the next invocation does not replace currentIndex in any previous timeout, since primitives (including numbers) are passed by value. Closure in JS can be a tricky thing.
The core problem is that your execution right now looks like:
for each item
wait
log
rather than:
for the current item
wait
log
repeat
Because JS is single-threaded (for most intents and purposes), setTimeout adds a callback to be executed later. It doesn't block until the timeout has expired, like a traditional sleep would do.

setInterval not continuing [duplicate]

This question already has answers here:
JS setInterval executes only once
(2 answers)
Closed 6 years ago.
I can't get this code to do anything beyond counting down to 29 from 30. Does anyone have any insight or hints as to what I am doing wrong to cause it to only run once? I checked to make sure that all the functions are being called with console.logs on game.time (except the clearInterval one since it stops already after the first time through). How do I get the setInterval to keep looping until 0? Thanks in advance for any help! :)
//game object to contain variables and methods
var game = {
// variable for time
time: 30,
// Start button onclick creates the time remaining object and calls the forloop to start
start: function() {
// $("#time").html(game.time);
game.countdown = setInterval(game.count(), 1000);
}, //end of start function
//what the set interval does which is subtract one second from game.time
count: function() {
game.time--;
// if statement to check when time gets to zero
if (game.time <= 0) {
game.stop();
}
// puts the current time left on the page
else {
$("#time").html(game.time);
}
}, // End of count function
// stops the set interval
stop: function() {
clearInterval(game.countdown);
}, // end of stop function
}; // end game object
// Start button click calls the start method
$("#start").click(game.start);
setInterval takes a function refererence as a parameter, it should look like:
setInterval(game.count, 1000)
When you write it as game.count(), you're calling the count() method once, which is evaluated immediately.
Then, setInterval's signature will use the return value from that method instead of a function reference:
setInterval(whatever_the_return_value_was, 1000);
By passing only the reference (as game.count), the timer should work as expected. It will call the reference by itself, every 1000ms.
(MDN docs)

understanding setInterval in javascript

I have a function which does something async like saving to database. Want a mechanism that first inserts the row and the next insertion should occur only when the first insert operation has finished.
Here is what I have tried and it somewhat works.
var interval = true;
function insert() {
model.save(function () {
interval = true;
})
}
foreach(row, function (key, val) {
var interval1 = setInterval(function () {
if (interval) {
insert();
interval = false;
clearInterval(interval1);
}
}, 100)
})
Is it the correct approach of doing this? Please shed some light about my understanding of timers in javascript.
No, you should not be creating timers to poll for when something is done. That's probably the worst way you can do it. What you want to do is to explicitly start the next iteration each time the previous one finishes.
Here's the general idea for how you do this without polling. The idea is that you need to create a function that can be called successive times and each time it's called, it will perform the next iteration. You can then call that function from the completion handler of your async operation. Since you don't have a nice convenient foreach loop to control the iteration, you then have to figure out what state variables you need to keep track of to guide each iteration. If your data is an array, all you need is the index into the array.
function insertAll(rows) {
// I'm assuming rows is an array of row items
// index to keep track of where we are in the iteration
var rowIndex = 0;
function insert() {
// keep going as long as we have more rows to process
if (rowIndex < rows.length) {
// get rows[rowIndex] data and do whatever you need to do with it
// increment our rowIndex counter for the next iteration
++rowIndex;
// save and when done, call the next insert
model.save(insert)
}
}
// start the first iteration
insert();
}
If you don't have your data in an array that is easy to step through one at a time this way, then you can either fetch each next iteration of the data when needed (stopping when there is no more data) or you can collect all the data into an array before you start the operation and use the collected array.
No, this is absolutely not the right way to do this. Lets assume that row contains 10 values, then you are creating 10 independent timers which continuously run and check whether they can insert. And it's not even guaranteed that they are executed in the order they are created.
As jfriend00 already mentioned, you should omit the "loop" and make use of the completion callback of the save operation. Something like this:
var rows = [...];
function insert(rows, index) {
index = index || 0;
var current_element = rows[index];
model.save(function() {
if (index < rows.length - 1) {
insert(rows, index + 1);
}
});
}
insert(rows);
Notice how the function calls itself (somehow) after the save operation is complete, increasing the index so the next element in the array is "saved".
I would use a library that handles async stuff such as async.js
BTW it seems like your model.save methods takes a callback, which you can use directly to call the insert method. And if the insert function is one you have made by yourself, and not a part of some bigger framework, I will suggest to re-write it and make take a callback as parameter, and use that instead of using setInterval for checking when async work is done.

The do-while statement [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
When is a do-while appropriate?
Would someone mind telling me what the difference between these two statements are and when one should be used over the other?
var counterOne = -1;
do {
counterOne++;
document.write(counterOne);
} while(counterOne < 10);
Or:
var counterTwo = -1;
while(counterTwo < 10) {
counterTwo++;
document.write(counterTwo);
}
http://fiddle.jshell.net/Shaz/g6JS4/
At this moment in time I don't see the point of the do statement if it can just be done without specifying it inside the while statement.
Do / While VS While is a matter of when the condition is checked.
A while loop checks the condition, then executes the loop. A Do/While executes the loop and then checks the conditions.
For example, if the counterTwo variable was 10 or greater, then do/while loop would execute once, while your normal while loop would not execute the loop.
The do-while is guaranteed to run at least once. While the while loop may not run at all.
do while checks the conditional after the block is run. while checks the conditional before it is run. This is usually used in situations where the code is always run at least once.
The do statement normally ensures your code gets executed at least once (expression evaluated at the end), whilst while evaluates at the start.
Lets say you wanted to process the block inside the loop at least once, regardless of the condition.
if you would get the counterTwo value as a return value of another function, you would safe in the first case an if statement.
e.g.
var counterTwo = something.length;
while(counterTwo > 0) {
counterTwo--;
document.write(something.get(counterTwo));
}
or
var counterTwo = something.length;
if(counterTwo < 0) return;
do
{
counterTwo--;
document.write(something.get(counterTwo));
} while(counterTwo > 0);
the first case is useful, if you process the data in an existing array.
the second case is useful, if you "gather" the data:
do
{
a = getdata();
list.push(a);
} while(a != "i'm the last item");

Categories

Resources