Following code is given:
var a = [ ], i = 0, j = 0;
for (i = 0; i < 5; i += 1) {
(function(c) {
a.push(function () {
console.log(c); });
})(i);
};
for (j = 0; j < 5; j += 1) { a[j](); }
Why does i always get bigger by 1 instead of staying 5? Hasn't the foor loop already been passed, so the i parameter given to the anonymous function should be 5?
If you referenced i from the inner closure then yes, you would see the result being 5 in all cases. However, you pass i by value to the outer function, which is accepted as parameter c. The value of c is then fixed to whatever i was at the moment you created the inner closure.
Consider changing the log statement:
console.log("c:" + c + " i:" + i);
You should see c going from 0 to 4 (inclusive) and i being 5 in all cases.
chhowie's answer is absolutely right (and I upvoted it), but I wanted to show you one more thing to help understand it. Your inner function works similarly to a more explicit function call like this:
var a = [ ], i = 0, j = 0;
function pushFunc(array, c) {
array.push(function () {
console.log(c);
});
}
for (i = 0; i < 5; i += 1) {
pushFunc(array, i);
}
for (j = 0; j < 5; j += 1) { a[j](); }
Which should also help you understand how c comes from the function argument, not from the for loop. Your inner function is doing exactly the same thing as this, just without an externally declared named function.
Related
I want to create a simple loop function that adds 2 every time it loops. However, even though I tell my for loop to stop if the number reaches or is less than 100, it goes past 100 and loops infinitely.
i++ works just fine:
function addTwo() {
for (i = 0; i <= 100; i++) {
console.log(i);
}
}
addTwo();
When I change it to i+2 it crashes:
function addTwo() {
for (i = 0; i <= 100; i + 2) {
console.log(i);
}
}
addTwo();
I expect the console to log:
0
2
4
6
8
...
100.
But instead it loops infinitely and crashes.
i+2 in your case does nothing. JS evaluates it and then does nothing with the calculated value, this means that i is never increased.
++ is a special operator that increments the variable preceding it by 1.
To make the loop work you have to assign the value of the calculation i+2 to the variable i.
for (i=0; i<=100; i = i+2) {
console.log(i);
}
or
for (i=0; i<=100; i += 2) {
console.log(i);
}
i++ increments i. But, i+2 doesn't update the value of i. You should change it to i += 2
function addTwo() {
for (i = 0; i <= 100; i += 2) {
console.log(i);
}
}
addTwo();
The third parameter of a for is the final-expression:
An expression to be evaluated at the end of each loop iteration. This occurs before the next evaluation of condition. Generally used to update or increment the counter variable.
In your case you are not assigning any value to i. You should replace it with something like this:
function addTwo() {
for (i=0; i<=100; i+=2) {
console.log(i);
}
}
addTwo();
i++ is a short hand for i += 1 which is called Increment Operator But i+2 or even i+1 will not increase the value of i. You need to increase it by assigning a new value to i. i = i + 2 or i += 2.
Number is one of the primitive types in javascript which mean you can't change it unless you use assignment operator =
Note: You are not using let or var with i this will make i a global variable.
function addTwo() {
for (let i = 0; i <= 100; i+=2) {
console.log(i);
}
}
addTwo();
for (i = 0; i <= 20; i++) {
console.log(i);
i++;
}
You can increase i twice Or
for (i=0; i<=100; i+=2) {
console.log(i);
}
you can use i+=2 it will increase value of i 2 times and set new value of i.
This question already has answers here:
JavaScript closure inside loops – simple practical example
(44 answers)
Closed 6 years ago.
I have a piece of code that I'm trying to have alert 1,2,3. I'm having issues using closures properly, so I can't figure this out.
The original code:
function buildList(list) {
var result = [];
for (var i = 0; i < list.length; i++) {
var item = 'item' + list[i];
result.push( function() {alert(item + ' ' + list[i])} );
}
return result;
}
function testList() {
var fnlist = buildList([1,2,3]);
// using j only to help prevent confusion - could use i
for (var j = 0; j < fnlist.length; j++) {
fnlist[j]();
}
}
testList();
I am trying to do something like this to buildList() to get it to work properly:
function buildList(list) {
var result = [];
for (var i = 0; i < list.length; i++) {
var item = 'item' + list[i];
result[i] = function(x) {
result.push( function() {alert(item + ' ' + list[x])} );
}(i);
}
return result;
}
I know I'm making mistakes on working with the closures, I'm just not sure what the problem is.
Your second try was closer to the solution but still doesn't work because your inner-most function is capturing variable item from your top-level function: item is just always referencing the same instance, which was created when calling buildList().
var scope in JavaScript is always bound to current function call, not to code block, so it's not bound to control statements like for.
For that reason, the alerts likely show the value 'item' + (list.length-1) had at the time of calling buildList().
Since you are passing i to your closure, you should declare var item within that function, e.g:
function buildList(list) {
var result = [];
for (var i = 0; i < list.length; i++) {
result[i] = function(x) {
// x and item are both local variables of anonymous function declared just above
var item = 'item' + list[x]; // or maybe you meant 'item' + x?
return function() {alert(item + ' ' + list[x])};
}(i);
}
return result;
}
Note that the closure would still capture a reference to list so will display the value it contains at the time of calling functions in the array returned by buildList(). Also local variable item is completely optional, you could call alert('item' + x /*or is it list[x]?*/ + ' ' + list[x]).
From How do JavaScript closures work?
Note that when you run the example, "item2 undefined" is alerted three
times! This is because just like previous examples, there is only one
closure for the local variables for buildList. When the anonymous
functions are called on the line fnlistj; they all use the same
single closure, and they use the current value for i and item within
that one closure (where i has a value of 3 because the loop had
completed, and item has a value of 'item2'). Note we are indexing from
0 hence item has a value of item2. And the i++ will increment i to the
value 3.
You need to make a closure in each loop iteration if you are to store the matching value of i:
function buildList(list) {
var result = [], item, closure;
for (var i = 0; i < list.length; i++) {
item = 'item' + list[i];
// call this function with the string you wish to store
// the inner function will keep a reference to the 'msg' parameter even after the parent function returns
closure = (function(msg) {
return function() {
alert(msg);
};
}(item + ' ' + list[i]));
result.push( closure );
}
return result;
}
function testList() {
var fnlist = buildList([1, 2, 3]);
// using j only to help prevent confusion - could use i
for (var j = 0; j < fnlist.length; j++) {
fnlist[j]();
}
}
testList();
Same question asked here and here. Same answers here, here, here, here and probably in dozen more places.
I need help in somewhere in javascript
var obj = jQuery.parseJSON(data.d);
This ajax call result returns some data (around 31).
Here is an example:
obj[0] = 10, obj[1]=20 ,obj[2]=30 , obj[4]=21,obj[5]=16,obj[6]=54 here I want to get value of
obj[0] and ob[4] using for loop . And I also need to do this for obj[10] and obj[14] the difference will be 5 between the i values .
Any idea or help?
You can do something like this (a pseudo code)
int i = 0;
while(i < 31)
{
print(i);
i = i + 4;
}
If i understood, you want to skip 5 on each step:
var array = 'abcdefghijklmnopqrstuvwxyz'.split(''); // something that generates an array just to show an example
var i = 0;
for (; i < array.length;) {
console.log(i, array[i]);
i += 5;
}
see fiddle
var iterator=0;
for (i = 0; i < obj.length; i++) {
if(i == iterator){
alert(obj[iterator]);
iterator= iterator + 4;
}
}
Here is my code. I do not quite understand why the for loop runs only once, both inner and outer. nodeList.length and innerNodeList.length show appropriate values when I generate alert messages. I see that both i and j do not increment beyond 0. Kindly point out anything wrong with the code.
function getCategoryElements() {
var newCategoryDiv = document.getElementById("category");
var nodeList = newCategoryDiv.childNodes;
for (var i = 0; i < nodeList.length; ++i) {
var innerNodeList = nodeList[i].childNodes;
alert("innerNodeList Length" + innerNodeList.length.toString());
for (var j = 0; j < innerNodeList.length; ++j) {
if (innerNodeList[j].nodeName == "SELECT") {
alert("inside select Node value " + innerNodeList[j].nodeValue.toString());
document.getElementById("newCategories").value =
document.getElementById("newCategories").value + '<%=delimiter%>' + innerNodeList[j].nodeValue;
} else if (innerNodeList[j].nodeName == "TEXTAREA") {
document.getElementById("newCategoriesData").value =
document.getElementById("newCategoriesData").value + '<%=delimiter%>' + innerNodeList[j].nodeValue;
}
}
}
}
var newCategoryDiv, nodeList, innerNodeList, innerNode, i, j;
newCategoryDiv = document.getElementById("category");
nodeList = newCategoryDiv.childNodes;
for (i = 0; i < nodeList.length; ++i) {
innerNodeList = nodeList[i].childNodes;
alert("innerNodeList Length" + innerNodeList.length.toString());
for (j = 0; j < innerNodeList.length; ++j) {
innerNode = innerNodeList[j];
if (innerNode.nodeName === "SELECT") {
alert("inside select Node value " + innerNode.nodeValue.toString());
document.getElementById("newCategories").value += '<%=delimiter%>' + innerNode.nodeValue;
} else if (innerNode.nodeName === "TEXTAREA") {
document.getElementById("newCategoriesData").value += '<%=delimiter%>' + innerNode.nodeValue;
}
// Will this work?
alert('Does this alert appear');
}
}
I took the liberty to refactor your code and clean it up a little bit. In case you're not aware, all variables have function scope in Javascript, so no matter where you declare them within a single function, Javascript treats them as if the variable declaration is the first statement.
It appears that your code is syntactically correct, and so I think that the most logical place to look for a problem is that there could be an error occurring after the last alert function call.
In order to check this, try adding another alert function call to the end of the inner loop. If it doesn't run, you'll know this is the case.
i = 3;
j = 2;
function domath(x) {
i = 4;
j = 1;
return i*x + j;
}
j = domath(i) - j;
alert(j); //expected result = 11
k = domath(i) + j;
alert(k); //expected result = 15
The above JavaScript code does not return the expected results (as indicated by the comments in the code). Please correct the code for me anyone ?
As you're not using var , the variables i and j you're defining in the first lines are actually the same variable as you define in your domath() function...
try this :
i = 3;
j = 2;
function domath(x) {
var i = 4;
var j = 1;
return i*x + j;
}
j = domath(i) - j;
alert(j); //expected result = 11
k = domath(i) + j;
alert(k); //expected result = 15
P.S : it could be a good idea to vary your variable name in order to make your code more readable
Declare your variables using var:
var i = 3;
var j = 2;
function domath(x) {
var i = 4;
var j = 1;
return i * x + j;
}
It seems to be a really nasty way to do things.
I would personally do something like:
var v1;
var v2;
function math(x){ //do math here then return}
alert(math(1))
If you really have to use the same varible every where at least do it like:
var i = 3;
var j = 2;
function domath(x) {
var i = 4;
var j = 1;
return i*x + j;
}
Also meaningful varibles names will keep you on a good track and using var and not global will also help you!
var i = 3;
var j = 2;
function domath(x) {
var i = 4;
var j = 1;
return i*x + j;
}
var x = domath(i) - j; // overwriting J will change your next expected result
alert(x); //expected result = 11
var k = domath(i) + j;
alert(k); //expected result = 15
The problem is you're overwriting global variables, i.e. screwing up your math:
j = domath(i) - j;
This expression is evaluated from left to right. The call to domath() will assign new values to i and j, so the effective code here would be this:
j = (i = 4) * 3 + 1 - 1;
So once this is done, j will be set to 12, which is indeed not 11. In addition, i will have a value of 4.
To use local variables within your function, you'll have to redeclare them, essentially hiding the global variables being outside this scope:
function domath(x) {
var i = 4;
var j = 1;
return i * x + j;
}
This time, the first assignment will be resolved to this, because domath() won't touch i and j assigned outside:
j = 4 * 3 + 1 - 2
Once this i done, j will be set to 11, just as expected.
To avoid such issues, it's good practice to always use var when defining new variables (which you'll have to do when wanting to write strict code anyway), and not to use such short, not-telling variable names. I'd consider limiting the use of one-character variable names to iterators and other things with very limited scope. Never for something being global.