最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

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

programmeradmin0浏览0评论

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.

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.

Share Improve this question edited Nov 13, 2015 at 1:54 royhowie 11.2k14 gold badges53 silver badges67 bronze badges asked Nov 13, 2015 at 1:29 MarkMark 12.6k6 gold badges24 silver badges38 bronze badges 3
  • 3 The final expression is only evaluated at the end of each loop iteration. rowName is undefined before then. See for @ MDN – showdev Commented Nov 13, 2015 at 1:36
  • 1 The 3rd (and 2nd) expression in the for loop isn't evaluated until the end of each iteration. If it were evaluated upfront to assign rowName, it would also immediately increment i to 1, skipping the initial value of 0. – Jonathan Lonowski Commented Nov 13, 2015 at 1:37
  • The documentation could hardly be clearer. It says "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." – user663031 Commented Nov 13, 2015 at 2:45
Add a ment  | 

4 Answers 4

Reset to default 5

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 parison ==
    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.

发布评论

评论列表(0)

  1. 暂无评论