简体   繁体   English

为什么这个简单的for循环不能按预期工作?

[英]Why doesn't this simple for loop work as expected?

One might expect the following to print out a , b , c . 人们可能希望以下内容打印出abc

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 . 相反,它打印出undefinedbc 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. 它打印undefinedbc的原因是因为for循环的工作方式。

for (initialization; condition; final expression)

Let's break down your for loop. 让我们分解你的循环。

initialization : i = 0 初始化i = 0

condition : i < 3 条件i < 3

final expression : i++, rowName = ['a', 'b', 'c'][i] 最终表达i++, rowName = ['a', 'b', 'c'][i]

When your loop is first entered, i is set to 0 . 首次输入循环时, i设置为0 This is the initialization step. 这是初始化步骤。 Then the condition step, i < 3 , is checked. 然后检查条件步骤i < 3 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. 在您的示例中,在根据当前索引将rowName设置为['a', 'b', 'c']的元素之前增加i

In your case, on the first iteration, rowName is undefined because the final expression is yet to be evaluated. 在您的情况下,在第一次迭代中, rowName undefined因为尚未评估最终表达式 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: 如果你想做一个棘手的单行for循环风格,“正确”的语法是:

var array = ['a', 'b', 'c'];
for (var i = 0, rowName; rowName = array[ i++ ]; ) {
    console.log(rowName);
}

Notice the ending ; 注意结局; of the for loop declaration. for循环声明。 There's technically an empty statement after the ; 从技术上讲,这是一个空洞的陈述; which is where you normally would do i++ . 这是你通常会做的i++

In this case, the "condition" of the for loop is taking advantage of the Javascript assignment operator. 在这种情况下,for循环的“条件”利用了Javascript赋值运算符。 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 . 因为在表达式内部, a = 1实际上返回1 And 1 is "truthy," meaning it evaluates to true in a boolean context like an if statement. 1是“truthy”,意味着它在布尔上下文中像if语句一样求值为true。

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 ). 它不会记录,因为a = 0返回0(以及将0赋值给a )。 And 0 is falsey. 0是假的。

This whacky for-loop syntax is only for certain conditions: 这种糟糕的for循环语法仅适用于某些条件:

  • 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. 如果任何数组元素是“假的”( nullundefined""等),它将过早地终止循环,因为运算符如上所述工作。
  • This assumes you don't care about the loop index i . 这假设您不关心循环索引i It will be off by 1 for every iteration of the loop, because i++ is executed before the for block. 对于循环的每次迭代,它将偏离1,因为i++for之前执行。 That is, the first time your for body executes, i will be 1, not its declared starting value of 0. 也就是说,你for身体第一次执行时, i将是1,而不是它声明的起始值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. 你在循环的每一步重新分配rowName ,并且开始时它是undefined 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. 真正的问题是,在满足循环的一个test之前for(assign; test; execute)内部的第三个条件才会execute If the test fails execute never happens. 如果test失败, execute永远不会发生。 If the test passes execute really begins after the first pass of the loop. 如果test通过execute确实在第一次循环后开始。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM