Closure in JavaScript from CoderSchool - javascript

I was doing some studying on CodeSchool. While watching a tutorial I was confused by an example. What they were trying to explain in the video was that closures created in loops won't bind until the last minute. The aim for this code was to take a name check for it in the array and return the name alone with its position(without the zero convention). Since closures don't bind till the last minute this code is returning z 5. I am confused why this code is returning a 5 and not a 4. The length of my array is 4 and the for loop stops before 4 because i < passengerArray.length which is the equivalent of i < 4 therefore the last index checked should be passengerArray[3] which means my (i+1) should be 4 in the end and not 5. I hope that makes sense. This has been bothering me all day.
function assignTorpedo(name, passengerArray)
{var torpedoassignment;
for(var i = 0; i < passengerArray.length; i++){
if(passengerArray[i] == name){
torpedoAssignment = function(){
console.log(name + " " + (i+1));
};
}
}
return torpedoAssignment;
}
var give = assignTorpedo("z",["z","a","b","c"]);
give();

The for loop ends when the test condition fails. Why does it fail? Because i is not less than 4; it's equal to 4. Thus, in the console.log() output you see 5.
Also, the statement
closures created in loops won't bind until the last minute.
is a strange way of describing how things work. As soon as the name is found in the array, the variable is assigned a reference to the constructed function. When assignTorpedo returns that value, the closure exists. In the closure, the value of the variable "i" is already 4.

The following statement increments i by 1 after each pass through the loop. So, after the fourth iteration i will be increased by one and tested against the condition again, and then it will fail.
var arr = ["z","a","b","c"];
for ( var i = 0; i < arr.length; i++ ) {
console.log( i );
}
console.log( i );

The For loop finishes when condition "i < passengerArray.length" being violated which i equals 4 at that time.
then console.log(name + " " + (4 + 1)));
Power Tip:
From one of my lecturers in uni,
"Think a "For" loop like a 'While' loop like this"
i = 0;
while (i < passengerArray.length)
{
...............
i++;
}

Related

Do While Loop where I console.log a phrase is the integer between 10-0?

I'm attempting to make a function wherein I console.log a phrase when the number is between 0-10.
I'm getting it to print out the phrase 10 times, but to get it to pass the testing platform, I need to print it out when the number is 0, and it's not passing.
function doWhileLoop(num) {
var i = 0;
function incrementVariable() {
i++
return i;
}
do {
console.log(i, "I run once regardless.");
}
while (incrementVariable() <= 9);
}
doWhileLoop(10);
Only print when incrementVariable() is less than the variable received:
function doWhileLoop(num) {
var i = 0;
function incrementVariable() {
i++
return i;
}
do {
console.log("I run once regardless.");
}
while(incrementVariable() <= num);
}
The point is that the loop condition must muse the parameter that is passed to the doWhileLoop function (while(incrementVariable() <= num)). And I guess the exercise is trying to show you that the code inside the do block will always run at least once, even if the condition in the while is false. So the following code runs once:
do {
console.log("I run once regardless.");
}
while(false);
Making this not count past 9
function doWhileLoop(num) {
if(num>9) {
num = 9;
}
var i = 0;
function incrementVariable() {
i++
return i;
}
do {
console.log("I run once regardless.");
}
while(incrementVariable() <= num);
}
Note, it is not clear to me whether you want it to print 10 times either 0 or 10 cannot be included. If you want it to print 0..10 that would actually be 11 times. So adjust the examples below as appropriate.
Note that while troubleshooting, it is helpful to print the value i, as I did in the examples below. When the program works as expected, you can then remove i from your console.log before for your final submission.
I also print out the final value of i when the loop is exited.
This is a god point of comparison for understanding how the loops, and the incrementation of values work in each case. It's also good to know how these loops leave variables that may be accessed later in a program, and serves as a comparison to the values printed.
The first two examples do not use a separate function just to increment, since incrementation itself is a function, and is built into the language. It also highlights how two variations the language provides for incrementing can be exploited in useful ways to control endpoint conditions such as this.
In all cases I consistently used i < num so the comparisons would hold.
Depending on your requirements, this could also be i < num+1 (equivalent to i <= num), or i < num-1. Adjusting this will increase or decrease the last/highest value of i that is printed, (and the value i has after the loop ends).
++i prints 10 times: when i is 0..9.
i === 10 when the loop ends.
(using i <= num would print 0..10 and exit with value 11)
function doWhileLoop(num) {
let i = 0;
do {
console.log(i, "I run once regardless. ");
}
while (++i < num);
console.log("Final value of i:", i);
}
doWhileLoop(10);
For comparison, this version,
i++ prints 11 times: when i is 0..10.
i === 11 when the loop ends.
(using i < num+1 would print 0..9 and exit with value 10)
function doWhileLoop(num) {
let i = 0;
do {
console.log(i, "I run once regardless. ");
}
while (i++ < num);
console.log("Final value of i:", i);
}
doWhileLoop(10);
The difference between ++i and i++ is that:
++i the increments i first, then uses new value to determine whether to run the loop again or not.
i++ determines whether or not to run the loop again first, based on the value i already has (and printed), then it increments i afterwards, but before runs the loop again (or before it exits, if the loop is not be be run again).
In your code, incrementVariable() acts exactly like my ++i example above, because the incrementVariable() function call is executed before the while comparison is made.
Another solution would be to use an if-then to constrain your print statement.
This version prints 10 times: when i is 0..9.
i === 10 when the loop exits.
(In this scenario you can control the final value of the loop, and the number of times the loop is run, independent from the values that are printed.)
function doWhileLoop(num) {
var i = 0;
function incrementVariable() {
i++
return i;
}
do {
if (i < num) {
console.log(i, "I run once regardless.");
}
}
while (incrementVariable() < num);
console.log("Final value of i:", i);
}
doWhileLoop(10);

javascript what is wrong with this "for" loop syntax?

Can someone please help me?
I am currently learning Javascript, and I don't understand what's wrong with the following piece of code:
var names = ["vasco", "joão", "francisco", "rita", "manuel"];
for (var i = 0; i < 4; i++); {
console.log("I know someone called " + names[i] + ".");
}
Arrays in JavaScript are zero-indexed. That means the element in the very first position is at index 0. To target that element, you can refer to it like names[0]. In your loop, you are iterating while i < 4, meaning once i becomes 4, the loop stops and does not continue. So you are only calling console.log 4 times. A common practice when iterating through an array is to say i < names.length. Also there are a couple syntax errors as others have pointed out. Below is a working version.
for (var i=0; i < names.length; i++) {
console.log ("I know someone called"+" "+names[i]+".");
}
because you terminate the for loop by semicolon(;) ,so for loop is seperated by its block .
then,
Ques1. what'll do next when code is run?
Ans. when execution comes to for loop, loop executes untill the value of i goes to 4 . then , the next block statement is executed.
Ques2. Why "manuel" is print in o/p?
Ans. answer is simple ,because foor loop terminates when value of i goes to 4 , so
console.log("I know someone called " + names[i] + "."); //it prints the arr[4]
You have ; at the end of your for, just remove it
Please remove the semicolon after the for to be:
var names=["vasco","joão","francisco","rita","manuel"];
for ( var i=0; i <5 ; i ++) {
console.log ("I know someone called"+" "+names[i]+".");
}
also the condition i<4 is the stopping the last case
there are two issues with the code you wrote ,
1- you have a semi-colon after the condition for(condition);
which result in the loop not doing anything
2- you are off by one, last element of the array has index 4
condition should be (i <= 4) or (i < array.length)
var names = ["vasco", "joão", "francisco", "rita", "manuel"];
for (var i = 0; i < names.length; i++){
console.log("I know someone called " + names[i] + ".");
}

Javascript stuck at "for" loop

i am newbie learner and i am learning basic javaScript from codecademy.I stuck at "Search Text for Your Name" tutorial 5/7.
here is my question:
your loop should stop when it hits the value of the first iterator (say, i)
plus the length of your myName variable.
here is some informations from to tutorial:
Your second "for" loop
Okay! Last loopy step: add another for loop, this time inside the body of your if statement (between the if's {}s).
This loop will make sure each character of your name gets pushed to the final array. The if statement says: "If we find the first letter of the name, start the second for loop!" This loop says: "I'm going to add characters to the array until I hit the length of the user's name." So if your name is 11 letters long, your loop should add 11 characters to hits if it ever sees the first letter of myName in text.
For your second for loop, keep the following in mind:
First, you'll want to set your second loop's iterator to start at the first one, so it picks up where that one left off. If your first loop starts with
> for(var i = 0; // rest of loop setup
your second should be something like
> for(var j = i; // rest of loop setup Second
think hard about when your loop should stop.
Finally, in the body of your loop, have your program use the .push() method of hits. Just like strings and arrays have a .length method, arrays have a .push() method that adds the thing between parentheses to the end of the array. For example,
newArray = [];
newArray.push('hello');
newArray[0]; // equals 'hello'
and here is my code:
multistr:true
var text = "Hey, how are you \
doing? My name is Emily.";
var myName = "Emily";
var hits = [];
for (var i = 0; i > text.length; i++)
{
if (text[i] === 'E')
{
for(var j = i; j > text.length; j++){
};
};
};
ps: i don't want to pass this tutorial without understand it. please help me. teach me.
for (var i = 0; i > text.length; i++) should be
for (var i = 0; i < text.length; i++)
otherwise it won't ever meet the criteria to even start the loop.
Welcome on board! You confused > with <. Your loops won't run because for the first check when i = 0 it certainly does not hold that 0 > text.length, because text.length is at least 0 (there are no strings shorter than the empty string).
You should make a habit of manually going through your loops for the first two steps and then check what happens just before the loop ends.
Here is what I got for my code:
for ( i = 0; i < text.length; i++)
{
if ( text[i] === "E")
{
for( var j = i; j < (myName.length + i ); j++)
{
hits.push(text[j]);
}
}
};
It looks like you were missing the " + i " part in your second for loop. That seems to make sure that the first loop will be included. I tried it without the "+ i" and it does not work.
I tried continuing directly from the second for loop using a "+ j" and that only crashes the browser.

Can someone please explain to me how the scope works for this array of anonymous functions?

Quite simply, I'd like to know why the call to arr0 seems to drag in the value of i instead of the one stored in the function at that position.
<script>
var arr = [];
for(var i = 0; i < 3; i++) {
//Assign anonymous functions to the array in positions 0 to 2
arr[i] = function() { console.log("function " + i); }
}
for(var i = 0; i < 3; i++) {
//The output for these function calls is correct!
arr[i]();
}
//Here I expected to output: function 0, but instead outputs: function 3 WTF!
arr[0] ();
</script>
Here's the output:
function 0
function 1
function 2
function 3
For the last call, i.e: arr[ 0 ] (); I expected the output to be "function 0", but surprisingly IT'S NOT... Could someone please care to explain why?
Thanks in advance!
Well this is a mixed bunch...
You are using the same i variable (despite "re-defining" it in the second loop, it's still the same i) that is placed in the global scope
As a result, in the second loop, each iteration alters the value of that global i, which results in the
function 0
function 1
function 2
function 3
output.
It was, by the way, absolutely not the expected result, if you used k in the second loop:
<script>
var arr = [];
for(var i = 0; i < 3; i++) {
//Assign anonymous functions to the array in positions 0 to 2
arr[i] = function() { console.log("function " + i); }
}
for(var k = 0; k < 3; k++) {
//The output for these function calls is correct!
arr[k]();
}
//Here I expected to output: function 0, but instead outputs: function 3 WTF!
arr[0] ();
</script>
That would produce:
function 3
function 3
function 3
function 3
and that is the infamous loop problem referred in the link above (in comments).
The reason is that functions, defined in your first loop (which, BTW, you should try to avoid in general case), "close" on the variables that are in the same scope as their definition - i in this case. That means that whenever value of i is changed later on, it will be reflected in that function.
The last example shows it in action - i is changed by the first for loop, so when the loop is finished - it's value is 3. All functions you defined now have the same value of i - 3.
To make the output like this:
function 0
function 1
function 2
function 0
you can do this (not that it's that great, structure wise):
var arr = [];
for(var i = 0; i < 3; i++) {
//Assign anonymous functions to the array in positions 0 to 2
arr[i] = (function(index){ return function() { console.log("function " + index); };}(i));
}
for(var k = 0; k < 3; k++) {
//The output for these function calls is correct!
arr[k]();
}
//Here I expected to output: function 0, but instead outputs: function 3 WTF!
arr[0] ();
That produces the ddesire result.
Here, you define an anonymous function:
(function(index){ ... }(i))
that is immediately invoked with i as a parameter. That parameter is referred to as index in the function body (not that it's important, even if you still called it i - it would work, since the "inner" i would shadow the "outer" one).
That function returns a function that has a different closure - on index, which is not important since index is not avialable after the immediately invoked function exists.
Another way would be using some sort of iterator - map, where supported, would do OK.
It's a common problem, after you've read the duplicate posted in the comments, here's a possible solution:
var arr = [0,1,2].map(function(i){
return function(){
console.log("function " + i);
};
});
for(var i = 0; i < 3; i++) {
arr[i]();
}
arr[0]();
By creating an isolate scope with map we avoid the problem altogether. Using underscore's _.range you could replace your loop patterns with:
_.range(0,10).map(function(index){
...
})
The question linked to in one of the comments will give you the general answer.
But I'll also specifically address what you're seeing here, because it might still be slightly confusing even after understanding the answers to the other question.
The main thing to realize here is that there is only one i variable. Even though it looks like you're declaring it twice with the var keyword, the second "declaration" is essentially ignored and treated like any ordinary assignment. You see, the for keyword does not introduce a new scope in JavaScript. So these two snippets are equivalent:
for (var i = 0; i < 3; i++) {}
And:
var i;
for (i = 0; i < 3; i++) {}
Once you realize that, and you get that the functions you create in the first loop all close over the same i, then you can understand why the second loop appears to be "correct" by your intuition: at the start of the loop you set i to 0, and then after each call you increment it. So even though all of them close over the same i, you're changing its value between calls!
And of course, for that last call, the value of i is still 3 since that's what it was at the end of the second loop and you didn't change it from that.

Attempt to add values to Array causes app to spin into an endless loop

for some sick reason, my check productIDs[addIndex] = allProductIDs[lastProductFoundIndex + i]; causes my app to spin into an infinite loop:
numberOfImagesToDisplay is set to 4
if (state == "next")
{
for(var a = 0; a < numberOfImagesToDisplay; a++) {
alert("a=" + a + ", numImages=" + numberOfImagesToDisplay)
if (a > 0) { addIndex = productIDs.length + 1; }
alert("I'm in GetNextProductIDs() 1");
//var lastProductFoundIndex = $.inArray(lastProductID, allProductIDs);
//alert("I'm in GetNextProductIDs() 2");
if (lastProductIndex >= 0) {
alert("I'm in GetNextProductIDs() 3");
//productIDs[addIndex] = allProductIDs[lastProductFoundIndex + i];
}
}
}
If I take out that line, it moves on.
Update: Resolved. lastProductIndex was not defined. So what was happening is that it would get there and the loop would end but it's weird because a callback was being called again when it should have ended. So that callback method kept calling this method and this method would end at that spot, the callback method would again be called, and so you had an endless loop.
That's very strange. All I can think is that you have an onpropertychange event firing that also modifies i. Major longshot, I know.
What if you add the var keyword to your for loop? That would turn it into a local variable instead of a global variable so no other function could inadvertantly trash your loop index.
for (var i = 0; i < numberOfImagesToDisplay; i++)
Note: You should have the var there whether or not that's the problem.
Update: What does alert("i="+i+", numImages="+numberOfImagesToDisplay) display each iteration through your loop? Do those variables have the expected values?
Are you sure this loop is stuck? Maybe it's another loop. Could it be that you're re-entering this loop repeatedly thereby getting repeated alerts? I just don't see how that line could cause this loop to become an infinite loop.
I don't see you incrementing variable a in there anywhere, but you're incrementing a variable i in your loop. a will therefore always be 0 -
for(var a = 0; a < numberOfImagesToDisplay; i++)
It's not related to your suspected problem line, but, at the line
for(var a = 0; a < numberOfImagesToDisplay; i++)
your setting a = 0 and the loop will run while a < numberOfImagesToDisplay. I dont see anywhere where you are incrementing or changing a to exit the for loop.

Categories