Why doesn't this simple for loop work as expected? - javascript

One might expect the following to print out a, b, c.
var i, rowName;
for (i = 0; i < 3; i++, rowName = ['a', 'b', 'c'][i]) {
console.log(rowName);
}
Instead, however, it prints out undefined, b, c. Why?
To clarify: I know how to make this work; what I'm curious about is why the above doesn't work.

The reason it prints undefined, b, c is because of how a for loop works.
for (initialization; condition; final expression)
Let's break down your for loop.
initialization: i = 0
condition: i < 3
final expression: i++, rowName = ['a', 'b', 'c'][i]
When your loop is first entered, i is set to 0. This is the initialization step. Then the condition step, i < 3, is checked. This is done before every iteration to decide whether or not to continue looping. After each loop, the final expression is evaluated. In your example, you increment i before setting rowName equal to an element in ['a', 'b', 'c'] based on the current index.
In your case, on the first iteration, rowName is undefined because the final expression is yet to be evaluated. Every iteration thereafter behaves as you would expect since a final expression has already been previously evaluated.

If you want to do the tricky one-line for loop style, the "correct" syntax is:
var array = ['a', 'b', 'c'];
for (var i = 0, rowName; rowName = array[ i++ ]; ) {
console.log(rowName);
}
Notice the ending ; of the for loop declaration. There's technically an empty statement after the ; which is where you normally would do i++.
In this case, the "condition" of the for loop is taking advantage of the Javascript assignment operator. If you have some code like this:
var a;
if( a = 1 ) { // Note this is assignment = not comparison ==
console.log('true');
}
It will log "true". Why? Because inside of an expression, a = 1 actually returns 1. And 1 is "truthy," meaning it evaluates to true in a boolean context like an if statement.
The opposite is also true, if your value is falsey:
var a;
if( a = 0 ) {
console.log('true');
}
It will not log, because a = 0 is returning 0 (as well as assigning 0 to a). And 0 is falsey.
This whacky for-loop syntax is only for certain conditions:
If any of the array elements are "falsey" (null, undefined, "", etc) it will prematurely terminate the loop, because of how operators work as mentioned above.
This assumes you don't care about the loop index i. It will be off by 1 for every iteration of the loop, because i++ is executed before the for block. That is, the first time your for body executes, i will be 1, not its declared starting value of 0.
The only benefit of this pattern is saving a few bytes. It's generally not used in the real world because of the above two pitfalls.

I think you want this?
var i, rowName;
for (i = 0; i < 3; i++){
rowName = ['a', 'b', 'c'][i];
console.log(rowName);
}

You are reassigning rowName at each step of the loop and it's undefined to begin with. Here's what you can do:
for(var i=0,rowName=['a','b','c'],l=rowName.length; i<l; i++){
console.log(rowName[i]);
}
or something like:
var rowName = ['a', 'b', 'c'];
for(var i=0,l=rowName.length; i<l; i++){
console.log(rowName[i]);
}
The real issue is that the third condition inside for(assign; test; execute) does not execute until until one test of the loop is satisfied. If the test fails execute never happens. If the test passes execute really begins after the first pass of the loop.

Related

What does this Javascript code mean?

I am trying to do a algorithm challenge. I saw this code from one of the completed answers. I am new to javascript so I am not completely sure of the code. I know that the first section of code pretty much takes the input and makes it to a map. Then init a matchingPair array and a counter. I am pretty much lost at the for loop section. Not too sure what matchingPairs[""+c[i]] = matchingPairs[""+c[i]] || 0; does. I am guessing the for loop is adding all the elements of matching pairs to the array and adding to counter.
function main() {
var n = parseInt(readLine());
c = readLine().split(' ');
c = c.map(Number);
var matchingPairs = {};
var matchingPairCount = 0;
for(var i=0; i< c.length; i++) {
matchingPairs[""+c[i]] = matchingPairs[""+c[i]] || 0;
matchingPairs[""+c[i]] += 1;
if (matchingPairs[""+c[i]] % 2 === 0) {
matchingPairCount += 1;
}
}
console.log(matchingPairCount);
}
A simpler example
a = {}
a["b"] = a["b"] || 0
console.log(a) // {b: 0}
a is set to an empty object. a["b"] is not yet set to anything, so when accessed it returns undefined.
Undefined is falsey - so this effectively sets a["b"] to 0.
Take another example;
a = {b: 5}
a["b"] = a["b"] || 0
console.log(a) // {b: 5}
The only difference in this example is that a["b"] is truthy (ie, it returns 5 rather than undefined).
This is a javascript way of setting a variable to a value only if it hasn't already been set to something else.
A string of space delimited numbers is supplied.
The counts of each number are calculated.
Each time a count is even then the matchingPairCount is incremented.
In short: it is counting pairs of matching numbers.
n is not used?

javascript Error - for loop

I wrote a this simple code in js.
var n=10;
for (i=1;i=n;i++){
console.log('avinsyh');
}
But the loop executes greater than 2000 and crashing the browser.Why this is happening so?
Note: If I Execute this:
var n=10;
for (i=1;i<n;i++){
console.log('avinsyh');
}
Then the javascritpt outputs the correct results
It's the assignment in the comparison part of the for loop, which makes an infinite loop. i becomes always n and evaluates to true.
for (i = 1; i = n; i++){
// ^^^^^
var n = 10,
i;
for (i = 1; i <= n; i++){
document.write('i: ' + i + '<br>');
}
in your first for loop , i=n will set i equal to the value of n and thus return a truthy value(as n is not 0) and you get a infinite loop.
In your for loop you are assinging the value i = n which is always true and hence results in infinite loop.
The condition expression is evaluated. If the value of condition is
true, the loop statements execute. If the value of condition is false,
the for loop terminates. If the condition expression is omitted
entirely, the condition is assumed to be true.
In your second case you are comparing the value of i on each iteration and hence you are getting the expected result.
The basic syntax of for loop is:
for ([initialExpression]; [condition]; [incrementExpression])
statement
So in your first case you are not providing the [condition] rather it is an assignment.

What does this for in loop mean and why it just prints out 0 and 1?

It is so funny that the following for in loop prints out 0 and 1.
Anybody helps to explain: 1 what does it mean for variable in a lambda function? 2. why prints out 0 and 1? (I changed the ['a', 'b'] to [1,2], it still prints 0 and 1.
for (var f in d = function(){}, ['a', 'b']){console.log(f)}
prints out
0
1
The
for (var f in d = function(){}, ['a', 'b']) ...
can be explained if you wrap the in clause into the parentheses:
for (var f in (d = function(){}, ['a', 'b']) )
where (d = function(){}, ['a', 'b']) is an expression enclosed in parentheses. The expression consists of 2 another expressions and a , operator.
, operator in turn evaluates both operands and returns the latter.
So in your case the d = function(){} assigns the anonymous function to a variable d and then the array with 2 elements is returned.
To summarize: the d = function(){} expression is not ignored and you can use d in the statements after this loop.
This is a weird behavior, but to elaborate this, the javascript for...in loop through values in an array, but this array is the last parameter.
for (var f in d =null, ['a', 'b']){console.log(f)} //prints 0,1
for (var f in null, ['a', 'b'],['a', 'b','c'],['a', 'b','c','d']){console.log(f)}//prints 0,1,2,3
so basically it does not matter what d is, or other parameters, the last parameter, in this example ['a', 'b','c','d'], is the array that this for loop loop through
also note
for (var f in d =function(){}, ['a', 'b']){console.log(d[f])} //prints undefined
print undefined. the ['a','b'] is not assigned to d
You are logging the key of the array, so since it has 2 entries, it prints out 0 and 1. Maybe this will help you understand
for(var key in array){
console.log(key, array[key]);
}
so the key (or index) would be a number representing where in the array your data is. You can then get your value by going array[key]

Javascript loop looses context in recursion

Here's an example:
function try2RecurseIt() {
var MyArr = [[1,[2,3],4],[5,6],[7,8,[9,0]]];
letsDance(MyArr);
}
function letsDance(arr) {
for (i=0; i<arr.length; i++) {
console.log("arr["+i+"] "+ arr[i]);
if (arr[i].constructor.toString().indexOf("Array") > -1) { // isArray check
letsDance(arr[i]);
}
}
}
I expected it would loop through all elements, but the result:
// arr[0] 1,2,3,4
// arr[0] 1
// arr[1] 2,3
// arr[0] 2
// arr[1] 3
Somewhere my letsDance() function loses context and I can't figure out where. What am I doing wrong?
Yes, I know about forEach, but I'm trying to understand where I'm wrong here. Further I'm going to use this method to parse htmlElements.children[n] which are not arrays.
I'm learning JavaScript and need to understand the basics without using any libraries.
Your problem is failure to keep variables local:
for (i=0; i<arr.length; i++) {
here, i becomes global on the first loop so subsequent loops increment it, use:
for (var i=0; i<arr.length; i++) {
The bug in your code is that i is a global variable. Therefore each call to the function rewrites the same i and i keeps being reset to 0.

weird syntax for "for" loop

Today I came across the following JS:
for (var b = k, d = function (c) {
// function body
}, a = b.p, e = z; 0 < c;) {
} // for loop closing cause
Can some please explain what's happening here? I'm confused about the function, normal "for" loop would do:
for(x=0; x<something; x++){
}
This loops appears to follow a different structure:
for(x=0; d = function(c), a = somevar, e = somevar, 0 < c)
Why are there 5 elements in the for loop? Thanks!
for (var b = k, d = function (c) {}, a = b.p, e = z; 0 < c;) {
} // for loop closing cause
for(x=0; x<something; x++)
If you map the first for loop with the signature for loop...
The code in bold is the declaration part for different variables that are going to be used inside the for loop.. .. Any number of variables can be declared here...
The second is the check condition...
And the third part is empty
There are not five parts, only three:
The first one contains four variable declarations (b, d, a and e).
The second one contains a comparison (0 < c).
The third one is empty.
Each part is separated by semicolons (;) and the variable declarations are separated by commas ,.
The first part is allowed to contain either an expression or a variable declaration list. For more information, have a look at the specification or the MDN JavaScript documentation:
initialization
An expression (including assignment expressions) or variable declaration. Typically used to initialize a counter variable. This expression may optionally declare new variables with the var keyword. These variables are not local to the loop, i.e. they are in the same scope the for loop is in. The result of this expression is discarded.
Only because for(x=0; x<something; x++) is the most typical form, does not mean others don't exist. Each part can contain an arbitrary expression. For example, a useful way to iterate over all children of a DOM element is the following:
for(var node = element.firstChild; node; node = node.nextSibling) {
}
First, node is initialised with the first child of the element. The second part just tests whether node is not null (you could also write node !== null explicitly) and the third part (executed after the iteration) assigns the next child to node.
Ill explain, but basically this is not good code.
Its not good code because you need to go online just to figure it out.
for (var b = k, d = function (c) {
// function body
}, a = b.p, e = z; 0 < c;) {
} // for loop closing cause
is the equivalent of
var b = k,
d = function (c) {
// function body
},
a = b.p,
e = z;
for (; 0 < c; ){
}
for loop parents has three parts
1. Initialization
2. Condition
3. Ending statement
That must all be separated by a ;
except these are all optional in a for loop
for (var init = 0; init < 10; init += 1) {}
same as:
var init = 0;
for (;;) {
if (!(init < 10)) {
break;
}
init += 10;
}
The control variables in a loop can also be a valid expressions as you have in your example.
The first loop you posted is slightly different from the last. The first declares and assigns several variables (one of which is a function), then provides a condition (0<c), then does nothing every iteration. The last seems invalid.
The problem with the first one seems to be only that it does not intialize a c, so unless c is a variable from outside of the scope of the loop that is somehow being changed inside its body, the loop will either not run at all (if c>=0) or it will run forever (if c is indeed less than 0).
for (var b = k, d = function (c) {
// function body
}, a = b.p, e = z; 0 < c;) {
} // for loop closing cause
as long as d is not 0 the for loop will run. d is 0 when 0 < c

Categories

Resources